Changelogs

Follow the improvements and fixes in each product release.

GT Page Blocks Builder

A free WordPress page builder plugin for HTML, CSS and JavaScript, with optional AI, live previews, reusable sections and theme regions.

Explore Product

Release History

Permalink

3.1.0

Adds Performance analysis to help identify expensive sections, reduces repeated CSS processing, and improves deferred loading and mobile editing.

  • Open Performance in the full-page builder, or Performance → Analyze section in the Block Editor inspector, to inspect unsaved source/minified sizes, expected CSS requests, duplicate CSS, and image/script/font hints.
  • Section CSS manifests are reused during each request, with invalidation after saves and recovery for missing files. In a local 100-section fixture, parsing fell from 101 passes to 1; this is not a claim about live PageSpeed savings.
  • Deferred styles use an external loader compatible with CSP policies allowing same-origin scripts. Nonce-only policies can authorize it through WordPress’s wp_script_attributes filter. The no-JavaScript fallback remains available.
  • Loading controls wrap on narrow screens.

Existing page content and loading choices remain unchanged. Deferral is opt-in; keep hero and shared layout styles inline or non-deferred. This release also includes the per-section Defer CSS option introduced in the locally deployed 3.0.4.

Validation: PHP/JavaScript regression suites, PHPStan, syntax checks, and local browser checks for CSP, no-JavaScript, print, and narrow-screen behavior. Full Gutenberg canvas browser verification is limited by the test browser’s blob-iframe rendering; both block registrations and inspector callbacks are covered by control-level tests.

Permalink

3.0.3

Fixes the preview jumping away while editing text directly in a hero or another section.

Inline text synchronization no longer triggers the HTML editor’s preview scrolling. Pending scrolls are cancelled when the code editor loses focus, while intentional navigation within the HTML editor still works.

Includes regression tests for inline edits, editor synchronization, and focus changes. No page-content changes or database migration are required.

Permalink

3.0.2

Fixes the 3.0.1 builder-preview regression that left later sections unstyled when an HTML container opened in one section and closed in another. Shared CSS can stay in the first section; existing page content needs no changes.

  • Track preview sections without adding wrapper elements, preserving shared containers and child/sibling selectors.
  • Keep cross-section opening and closing tags intact during inline text edits.
  • Remove deleted CSS declarations from the live preview and rebuild the complete document when HTML changes.
  • Add DOM regression tests for shared containers, section selection, duplicate text, and minified preview markup.

Validated with 49 WordPress integration tests, 28 PHP unit tests, 7 JavaScript DOM tests, PHPStan, syntax checks, and local/live browser checks of the affected homepage.

Permalink

3.0.1

Page Blocks Builder 3.0.1 adds automatic Functionalities compatibility in the builder preview and optional CSS files for individual sections. Selecting or editing preview text follows the matching section, and saving preserves selection, WordPress blocks, and newer edits made during the request.

Each CSS file uses the page ID and a five-character ID that changes on save. Existing sections remain inline unless file output is selected, with inline fallback when files cannot be written.

Validation: 76 plugin tests, PHPStan, PHP/JavaScript syntax checks, and browser checks of fonts, section selection, saving, and stylesheet output.

Licensed updates now accept packages from the exact configured HTTPS R2 bucket. The license server retains its authenticated redirect for remote clients on 3.0.0 or older.

Permalink

3.0.0

A correctness release. It repairs paths that silently corrupted or discarded work, gives the plugin a test suite and CI for the first time, and makes the upgrade itself verifiable.

Back up your database before upgrading — the schema change is one-way. Requires PHP 8.1. Flush your page cache and CDN afterwards: generated CSS and JS filenames now carry a content hash.

Breaking

  • PHP 8.1 is the minimum. WordPress will not offer this to a site below it, and activation stops with a notice instead of a white screen.
  • The CSS minifier no longer collapses whitespace around :. .menu :hover stays a descendant selector instead of silently becoming .menu:hover. If a stylesheet unknowingly depended on the collapsed form, that rule changes what it matches — this fixed eight blocks on our own site whose typography had quietly stopped applying.
  • Minified JavaScript changes shape. A line comment no longer swallows the rest of the file, and newlines survive so semicolon-free code is not concatenated. Blocks whose JS silently did nothing start working.
  • Generated asset filenames carry a content hash. Every cache and CDN misses once. The old unhashed name is still written as a copy for this major version.
  • Utility-class output is switched off once during the upgrade, with a notice. The scanner never emitted anything for page blocks, so this is a zero-visual-change upgrade; turning it back on is your decision.
  • PHP execution in the block preview requires administrator access. It previously ran for anyone who could edit the post.
  • The AI panel requires manage_options. Restore with add_filter( 'gt_pb_ai_capability', fn() => 'edit_posts' );.
  • The undocumented terminal endpoint is removed.
  • Uninstalling deletes options, transients and stored AI keys. The library is dropped only if you tick the new setting.
  • Library usage counts change on block themes, where the invalidation hooks were never registered.

Correctness

Editing a library block reaches the visitor — in file-output mode the generated file was written once and never again. The builder stops blanking core and third-party blocks on every keystroke. Renaming a section persists. A failed save says so instead of showing a green notice over a discarded session. Inline SVG backgrounds survive the CSS sanitiser. A block detached from the library stops rendering the library version over your own copy.

Recovery

Library blocks keep a revision history with one-click restore. Document-level undo covers add, delete, duplicate, reorder and import. Cmd+Backspace and Cmd+D stop acting on the whole section from inside a code pane. Undo after switching sections no longer pastes the previous section’s code.

Security

The PHP-execution checksum is keyed with the site salt, so it cannot be recomputed by whoever wrote the row; existing blocks keep working and are re-keyed in the background. The licence and update channel verifies TLS certificates and rejects package URLs that are not HTTPS on the licence host.

Free, with licensed updates

Every feature works without a licence key; nothing is gated. A licence buys automatic updates and support. Security releases reach every install regardless, through a separate channel — see SECURITY.md.

Going back

Reinstall v2.8.1. The database stays at schema 1.2, which is expected and harmless. PHP-enabled blocks strip their tags until re-saved. Detail in README.md under “Going back from 3.0.0”.

Permalink

2.8.1

Security release. Update before anything else.

Privilege escalation in the block preview. PHP in a Page Block no longer runs for users who can merely edit the post. The builder’s preview endpoint is reachable by anyone with edit_post — an Author, or a Contributor on their own draft — and it executed the section’s PHP after deriving the content checksum from the very content it was about to run, so the check was satisfied by definition. On any site that had turned PHP blocks on, that left the site-wide constant standing alone as the only gate. Running PHP in a preview now requires administrator access, and everyone else previews with the tags stripped and a note saying so rather than silently different output.

The update channel verifies certificates again. It was requesting with sslverify off, and the server’s reply supplies the package URL WordPress downloads and installs a plugin from, so anything able to answer as the licence server could have installed arbitrary code. Certificates are now verified, the request goes through wp_safe_remote_post(), and any package, url or homepage pointing somewhere other than the licence server’s own host is discarded rather than followed. A host with a genuinely broken CA bundle can opt out per-site with GT_PB_LICENSE_INSECURE. The changelog the update screen renders is escaped before display.

The plugin declares what it needs. Requires PHP: 8.1, Requires at least: 6.0, a licence and a text-domain path. It previously declared none, so WordPress offered the update to sites that would fatal on it, and the update payload separately claimed PHP 7.4 while the code has needed 8.1 since 2.7. A site below 8.1 now gets an admin notice naming the versions instead of a white screen. Update URI is set, so the plugin can only ever be updated from its own source.

The licence screen is reachable. It is registered under the Page Blocks menu, but the Plugins row action and both admin notices linked to options-general.php, a screen that does not exist.

Also: the preview endpoint checks the post type, matching the builder; and the GPLv2 text the header declares now ships with the plugin.

Permalink

2.8.0

  • The library shows what each block looks like. Every thumbnail was an empty frame: the preview document was escaped into an HTML attribute by a helper that handles &, < and > but not quotes, so each one was cut off at the quote in its own charset tag. Blocks with no markup to render — CSS-only token blocks, PHP-only blocks — say so instead of showing an empty rectangle, and thumbnails render at a desktop width and scale down, so a section built for 1200px shows the layout it actually produces.
  • Each block reports how many posts and pages place it, counted across both the editor block and the shortcode. That is the number that tells you whether a block is safe to delete. Counted in a single pass and cached, so a library of two hundred blocks does not mean two hundred table scans to draw one screen.
  • Bulk selection with duplicate, trash, restore and delete forever; sorting by recently updated, title, most used or least used; and a grid/list switch that remembers which you prefer. The shortcode is now a chip you can see and click to copy rather than an action that copied it silently.
  • Import in Page Settings is two buttons, add or replace, instead of one dialog whose Cancel meant “replace every section”. Only replace confirms, and it says how many blocks the builder cannot rebuild are about to go.
  • A Build button in the block editor saves the page and opens it in the visual builder. The builder reads from the database, so saving first is what keeps unsaved editor changes from being silently absent.
  • The library and settings screens now follow the admin around them: WordPress’ own status filters, search box, view switcher and row actions, real section headings instead of headings faked with table cells, and no inline styles left in the settings template.
  • Fixed: block toolbar buttons were two different heights, 26px and 29.6px, because one of them was never given a height — it inherited whatever the editor’s line-height produced, and WordPress 7 changed that. Both are pinned now, and the icons are 18px rather than 14px.
  • Fixed: the settings screen still documented the old md_ filter name for preview injection. It shows gt_page_blocks_builder_preview_injection.
Permalink

2.7.5

  • Fixed: the section panel vanished off the right edge once the AI assistant had filled the code editors. Nothing was hiding it — the builder had grown wider than the window, and the panel is the last column of that row. The code area was reporting its own content width as a minimum, which with the assistant open kept the whole builder above 1552px; a 14-inch laptop is 1512. It now fits from 1920px down to 1000px with the panel fully visible, and the tag-snippet toolbar scrolls inside its own bar instead.
  • Import in Page Settings is two buttons, Import & add and Import & replace. It was one button behind a dialog whose Cancel meant “replace every section” — the destructive choice sitting on the dismissive button. Only replace asks for confirmation, and it says how many blocks the builder cannot rebuild are about to be removed.
  • Page Settings opens with a count of what is on the page, reports the result of an import or export inline instead of through a browser alert, and stays open while you work. Exported files are named after the page rather than its post ID.
  • The AI model list keeps only the GPT-5.6 family: Sol, Terra and Luna. A site still set to an older model falls back to the default rather than sending one the API would reject.
Permalink

2.7.4

  • The two builder filters and the four helper functions now carry the gt_ prefix, matching everything else the plugin exposes: gt_page_blocks_builder_preview_injection, gt_page_blocks_builder_post_types, gt_page_blocks_builder_url(), gt_page_blocks_builder_post_types(), gt_page_blocks_builder_nonce_action() and gt_page_blocks_preview_nonce_action().
  • Every old md_-prefixed name still works. The filters run immediately before their replacements, so the current one has the last word, and the functions delegate to theirs. Each points at its replacement under WP_DEBUG while in use and is silent otherwise, so existing snippets keep working and nobody gets a notice for a hook they never touched.
  • gt_page_blocks_builder_nonce_action() still returns its original string. It identifies nonces already issued into open builder tabs and saved URLs, and renaming the value would invalidate them for nothing.
Permalink

2.7.3

  • Page settings live in one dialog. Title, slug, template, import and export are page-level rather than section-level, so they sit together behind one button instead of being spread across the top bar and the section panel. The slug shows the permalink it will produce, and WordPress’ own sanitised result is adopted after saving rather than what was typed.
  • Sections get an id. Where the outermost element has none, the builder writes one in — an id you wrote yourself is never touched. The edit is made on the opening tag as text rather than by reparsing the markup, so quote style, self-closing tags and indentation survive, a &gt; inside an attribute value does not end the tag early, and data-id= is not mistaken for id=. Sections named after a generated id are listed by their first ten characters of text instead.
  • Every section drags, from anywhere on its row. Reordering was HTML5 drag-and-drop on a row covered by buttons, and a mousedown on a form control does not start its draggable ancestor’s drag — in practice only a 14px grip worked. Locked and linked sections reorder too, a drop can land past the last row, and the drop point is shown while dragging.
  • Clicking anything in the preview selects the section it belongs to, without disturbing the inline edit the same click opens.
  • The AI assistant applies its own answers. A reply lands in the section and the preview updates, rather than arriving as code to copy into the editor beside it; bundled CSS and JS are unpacked into their own panes, so one prompt can fill all three. Undo restores the section exactly. A “Whole page” toggle sends every section’s code with the prompt, so generated markup matches the class names, spacing and variables already on the page.
  • Latest AI models, and one list behind them. The model list was duplicated in four places and had already drifted — the registered default and the request-path fallback named different models, so a saved choice could be silently replaced. GPT-5.6 Luna is the new default, alongside the Claude 5 family.
  • Locked blocks can be deleted from the section panel. Locked means the builder will not rewrite a block’s markup, not that the block has to stay on the page. It asks first, and the save guard that refuses to drop blocks the builder cannot rebuild stays exactly as strict. Their empty code panes are hidden.
  • The builder keeps its own palette on any theme. It renders on a front-end route, so the active theme’s stylesheet loads beside it — and themes style bare select, input, textarea, pre and details under a [data-theme] ancestor, which outranked the builder’s own rules. Controls were wearing the theme’s dark palette while the chrome around them stayed light, a tiled dropdown arrow filled the model picker with black triangles, and stray label and textarea margins pushed controls off their rows. The preview iframe had the mirror-image problem: a transparent body took the operating system’s dark canvas while the theme supplied its light-mode text.
  • Detach a copy is a real button again, with a broken-link icon. It carried two class names this plugin has never defined and fell through to the browser’s default.
  • Plainer names in the code toolbar: wpauto is Auto-format, PHP is Run PHP, and the bare “JS:” prefix is a Script label. The AI composer sends on Enter, so its button is an arrow.
Permalink

2.7.2

Fixed

Scrolling was slow, or stalled entirely, while blocks showed their visual preview.

Every Page Block in preview mode is a separate document carrying the whole theme stylesheet set — measured at roughly 25 stylesheets and 2,200 CSS rules to style about 30 elements, duplicated per block. A page of eight blocks therefore kept around 200 stylesheets and 17,600 rules alive at once, each in its own compositing context, and scrolling paid for all of it. Switching a block to code mode destroyed its frame, which is why code mode always felt fine.

Previews are now mounted only while within 800px of the viewport and unmounted beyond it. On a 12-block page that means at most 3 frames live instead of 12, and 75 stylesheets instead of 300. A holder element retains each frame’s measured height whether or not it is mounted, so unmounting never collapses a block or moves the scroll position.

Preview fidelity is unchanged: a mounted frame still loads the full theme stylesheet set and theme.json global styles.

Permalink

2.7.1

Fixed

Code editors were unusable inside the block canvas. wp.codeEditor loads into the admin document, but the block canvas has been an iframe since WP 6.3. A CodeMirror mounted there resolves focus and key events against the outer document, so it rendered correctly and could not be clicked into or typed in. The plain textarea is now used there, as core’s Custom HTML block does. Tab in that textarea also silently discarded its indent; it now commits properly.

Block editor UI shipped unstyled. Styles enqueued for the editor only reach the outer admin document, so the block’s own chrome had no CSS and the device-preview controls rendered as blank squares with no dashicons. The stylesheet is now registered as the block’s editor_style, which is what gets it into the canvas.

Inline block CSS could be silently dropped. Whether a block emitted its &lt;style&gt; was gated on a request-global flag raised by any block on the queried post. A block rendered from a widget, synced pattern, or template part was silenced by a flag raised on another block’s behalf. CSS is now tracked per block.

minify_css corrupted quoted strings and math functions. [style*="font-weight: 300"] and [style*="font-weight:300"] are different selectors; collapsing the space merged them. Separately, clamp(6.75rem, 6rem + 2.2vw, 9rem) requires the spaces around +, while the sibling combinator requires collapsing them. Both are now handled.

Changed

  • Previews load theme.json global styles alongside every theme stylesheet, so var() resolves as it does on the front end.
  • The CSS editor suggests the custom properties the active theme defines, harvested from its stylesheets and theme.json.
  • The block editor chrome now follows the WordPress admin: its palette, 2px radii, system font, and standard button treatment.
  • The format toggle applies wpautop(), matching its label, instead of running the whole the_content filter chain from inside a block that is itself rendering during the_content.