Page Builders and Commercial Themes
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This sub-section’s WordPress bibliography lists the reference material consulted while preparing these pages. |
A large part of the WordPress ecosystem sells design tools rather than designs: page builders, plugins that replace or extend the editor with their own layout system, and multipurpose themes, general-purpose themes configured through many options and usually sold with a paid add-on. Older books present them as the normal way to design a site. This page describes them neutrally, as one option next to block themes, for site owners choosing a design approach and for developers who inherit a site built with one of them.
This page was written against WordPress 7.1.3 (released 2026-10-06; PHP 7.4 minimum, 8.3+ recommended; 7.1.4, a security
release of 2026-10-28, is the version to run in production), the bundled Twenty Twenty-Five 1.5 block theme and WP-CLI
2.12.0, and checked on 2026-10-28. The products were installed from their
WordPress.org listings in the versions current on that date: Elementor 4.3.5, GenerateBlocks 2.5.0, Kadence Blocks
3.8.0.2, Astra 4.14.1, GeneratePress 3.6.1 and Kadence 1.5.2. Every output block below is real output from a
WordPress 7.1.3 site (wordpress:7.1.3-php8.4-apache, MariaDB 11.8). Products change quickly; the internals shown
(meta keys, option names, asset handles) belong to these versions, not to any WordPress API. WordPress 7.2, in beta and
due in December 2026, does not change anything described here so far.
No product here is recommended over another, and none is required: core blocks, patterns and a block theme (Themes Overview) cover the same ground.
What page builders and multipurpose themes are
A page builder gives editors a visual layout tool: rows, columns, widgets or blocks with many design controls (spacing, borders, backgrounds, motion, per-device visibility). There are two families, and the difference decides how much lock-in a site accepts:
-
Editor-replacing builders open their own editing screen and store the page in their own format, outside the block markup that WordPress understands. Elementor is the best-known example.
-
Block-based builders add blocks to the core block editor. The page stays block markup in
post_content, but the blocks, their attributes and their generated CSS belong to the plugin. GenerateBlocks and Kadence Blocks are examples.
A multipurpose theme is a classic or hybrid theme meant to fit any site: header and footer builders in the Customizer, dozens of layout options, page-level settings and imported "starter sites". GeneratePress, Astra and Kadence (theme) are examples; each is free in the Theme Directory with a paid add-on sold by the vendor.
| Product | Kind | Free / paid split |
|---|---|---|
Editor-replacing page builder (plugin) |
Free plugin; paid "Pro" plugin adds widgets, theme building and forms |
|
Block-based builder (plugin) |
Free plugin; paid "Pro" add-on |
|
Block-based builder (plugin) |
Free plugin; paid "Pro" add-on |
|
Multipurpose classic theme |
Free theme; paid premium version sold by the vendor |
|
Multipurpose classic theme |
Free theme; paid add-on sold by the vendor |
|
Multipurpose classic theme |
Free theme; paid add-on sold by the vendor |
The free parts are GPL software in the official directories. The paid add-ons are sold and updated by the vendors, so their updates depend on an active licence (see Choosing and Managing Plugins and Themes for freemium rules and update channels). WordPress.org also keeps a list of commercially supported GPL theme companies, which is a directory, not a recommendation.
Builders and multipurpose themes became popular when core had no layout tools: before 5.0 (2018) the editor was a single
TinyMCE field, and before 5.9 (2022) there was no Site Editor. Core has since added most of what builders were bought
for: columns, groups and grid layouts, global styles in theme.json, patterns, template editing, responsive styles
(7.1) and per-block custom CSS (7.0). See Site Editor and Global
Styles.
The storage format decides lock-in. A page made of core blocks is HTML with block comments that any theme renders and
the core editor edits. An editor-replacing builder keeps the layout in private post meta and leaves only a plain-HTML
copy in post_content; a block-based builder keeps block markup, but with its own block names, attributes and
generated CSS; a multipurpose theme keeps content ordinary but holds the header, footer and look in its own options and
page meta. The next sections show each case on a real page.
A test site
The examples use the standard local stack from
Local Development Environments (any WordPress 7.1.3 site with
WP-CLI works; the one in Database Schema was used). The
products are installed from WordPress.org but not activated yet, and the baseline page for the Lumen Press spring
catalogue (block-page.html) uses core blocks only:
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">Spring 2027 catalogue</h1>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="/books/">Browse the catalogue</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons -->
wp plugin install elementor generateblocks kadence-blocks
wp theme install astra generatepress kadence
wp rewrite structure '/%postname%/'
wp post create ./block-page.html --post_type=page --post_title="Spring catalogue (blocks)" \
--post_name=spring-blocks --post_status=publish
An Elementor page saved from WP-CLI
Elementor normally saves from its own editor screen. The same save can be run from WP-CLI through the plugin’s document manager, which is useful for scripted tests and for understanding the stored format. With Astra active and Elementor activated, this script creates the same page as Elementor data (a container holding a heading, a text and a button widget):
<?php
// Run with: wp eval-file elementor-page.php --user=admin
$page_id = wp_insert_post( array(
'post_type' => 'page',
'post_title' => 'Spring catalogue (Elementor)',
'post_name' => 'spring-elementor',
'post_status' => 'publish',
) );
$document = \Elementor\Plugin::$instance->documents->get( $page_id );
$document->set_is_built_with_elementor( true ); // Sets _elementor_edit_mode = builder.
$document->save( array(
'elements' => array(
array(
'id' => 'a1b2c3d',
'elType' => 'container',
'settings' => array(),
'elements' => array(
array( 'id' => 'e4f5a6b', 'elType' => 'widget', 'widgetType' => 'heading', 'elements' => array(),
'settings' => array( 'title' => 'Spring 2027 catalogue', 'header_size' => 'h1' ) ),
array( 'id' => 'c7d8e9f', 'elType' => 'widget', 'widgetType' => 'text-editor', 'elements' => array(),
'settings' => array( 'editor' => '<p>Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p>' ) ),
array( 'id' => 'f0a1b2c', 'elType' => 'widget', 'widgetType' => 'button', 'elements' => array(),
'settings' => array( 'text' => 'Browse the catalogue', 'link' => array( 'url' => '/books/' ) ) ),
),
),
),
) );
WP_CLI::success( "Elementor page {$page_id} saved." );
Source: WP-CLI Commands: wp eval-file
wp theme activate astra
wp plugin activate elementor
wp eval-file elementor-page.php --user=admin
wp post meta list 8 --format=table
wp post get 8 --field=post_content
Success: Elementor page 8 saved.
post_id meta_key meta_value
8 _elementor_edit_mode builder
8 _elementor_data [{"id":"a1b2c3d","elType":"container","settings":[],"elements":[{"id":"e4f5a6b","elType":"widget","settings":{"title":"Spring 2027 catalogue", …
8 _elementor_page_assets a:2:{s:6:"styles";a:1:{i:0;s:14:"widget-heading";}s:7:"scripts";a:1:{i:0;s:18:"elementor-frontend";}}
8 _elementor_template_type wp-page
8 _elementor_version 4.3.5
8 _elementor_global_class_usage_indexed 1
8 _elementor_global_class_usage_indexed_preview 1
<h1>Spring 2027 catalogue</h1> <p>Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p> <a href="/books/">
Browse the catalogue
</a>
The design lives in _elementor_data; post_content holds a stripped HTML copy without block delimiters, classes
or layout. Without _elementor_edit_mode set to builder, Elementor ignores its data and shows post_content.
Activation also created a "Default Kit" post of type elementor_library (global colours and fonts) and about a dozen
elementor_* options. Under PHP 8.4 the plugin’s logger printed deprecation notices after each WP-CLI command.
A GenerateBlocks page
A block-based builder stores ordinary block markup with its own block names. This page uses two GenerateBlocks 2.x
blocks, generateblocks/element (any container tag) and generateblocks/text (any text tag); the editor turns their
styles attribute into the css attribute:
<!-- wp:generateblocks/element {"uniqueId":"lp01hero","tagName":"section","styles":{"backgroundColor":"#f7f3ec","paddingTop":"4rem","paddingBottom":"4rem"},"css":".gb-element-lp01hero{background-color:#f7f3ec;padding-bottom:4rem;padding-top:4rem}"} -->
<section class="gb-element-lp01hero"><!-- wp:generateblocks/text {"uniqueId":"lp01head","tagName":"h1","styles":{"color":"#b3261e","fontSize":"3rem"},"css":".gb-text-lp01head{color:#b3261e;font-size:3rem}"} -->
<h1 class="gb-text gb-text-lp01head">Spring 2027 catalogue</h1>
<!-- /wp:generateblocks/text -->
<!-- wp:generateblocks/text {"uniqueId":"lp01text","tagName":"p"} -->
<p class="gb-text">Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p>
<!-- /wp:generateblocks/text -->
<!-- wp:generateblocks/text {"uniqueId":"lp01link","tagName":"a","htmlAttributes":{"href":"/books/"},"styles":{"backgroundColor":"#b3261e","color":"#ffffff","paddingTop":"0.75rem","paddingRight":"1.5rem","paddingBottom":"0.75rem","paddingLeft":"1.5rem"},"css":".gb-text-lp01link{background-color:#b3261e;color:#ffffff;padding:0.75rem 1.5rem}"} -->
<a class="gb-text gb-text-lp01link" href="/books/">Browse the catalogue</a>
<!-- /wp:generateblocks/text --></section>
<!-- /wp:generateblocks/element -->
wp theme activate generatepress
wp plugin activate generateblocks
wp post create ./gb-page.html --post_type=page --post_title="Spring catalogue (GenerateBlocks)" \
--post_name=spring-gb --post_status=publish --porcelain
Source: WP-CLI Commands: wp post create
On the front end the plugin printed these rules in a generateblocks-inline-css style element. The colours are
literal hex values, not theme.json presets, so a later palette change in the theme does not reach these blocks.
What deactivation leaves behind
Deactivating the product is the quickest lock-in test: the content that stays readable is what a migration starts from.
Elementor
With Elementor deactivated, Astra renders the page from post_content, and the automatic paragraph filter (wpautop)
wraps the leftover whitespace:
wp plugin deactivate elementor
curl -s https://lumenpress.test/spring-elementor/ | sed -n '/<div class="entry-content/,/<\/div>/p'
Source: Code Reference: wpautop()
<div class="entry-content clear"
itemprop="text">
<h1>Spring 2027 catalogue</h1>
<p>Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p>
<p> <a href="/books/"><br />
Browse the catalogue<br />
</a></p>
</div><!-- .entry-content .clear -->
The text and the link survive; the container, the button styling and every design setting do not. In the block editor the page has no block delimiters, so it opens as a single Classic block. A short script shows how the editor sees both builder pages, with Elementor and GenerateBlocks deactivated:
<?php
// Run with: wp eval-file parse.php
foreach ( array( 'spring-elementor', 'spring-gb' ) as $slug ) {
$page = get_page_by_path( $slug );
$blocks = array_filter( parse_blocks( $page->post_content ), fn( $b ) => null !== $b['blockName'] || '' !== trim( $b['innerHTML'] ) );
foreach ( $blocks as $block ) {
$name = $block['blockName'] ?? '(freeform: Classic block)';
$registered = $block['blockName'] && WP_Block_Type_Registry::get_instance()->is_registered( $block['blockName'] ) ? 'registered' : 'not registered';
WP_CLI::line( "{$slug}: {$name} ({$registered})" );
}
}
Source: Code Reference: parse_blocks()
spring-elementor: (freeform: Classic block) (not registered)
spring-gb: generateblocks/element (not registered)
Uninstalling does not clean up either. Elementor’s data stayed in the database after wp plugin uninstall, which runs
the plugin’s uninstall routine and deletes its files:
SELECT 'postmeta' AS source, COUNT(*) AS row_count FROM wp_postmeta WHERE meta_key LIKE '\_elementor%'
UNION ALL SELECT 'options', COUNT(*) FROM wp_options WHERE option_name LIKE 'elementor%' OR option_name LIKE '\_elementor%'
UNION ALL SELECT 'elementor_library posts', COUNT(*) FROM wp_posts WHERE post_type = 'elementor_library';
Source: WP-CLI Commands: wp db query
wp db query < count.sql
wp plugin uninstall elementor
wp db query < count.sql
source row_count
postmeta 11
options 12
elementor_library posts 1
Uninstalled and deleted 'elementor' plugin.
Success: Uninstalled 1 of 1 plugins.
source row_count
postmeta 11
options 12
elementor_library posts 1
Keeping data lets a reinstall restore every page, but leaves cleanup to the site owner; an empty
wp-content/uploads/elementor/ directory also remained.
GenerateBlocks and other block-based builders
With GenerateBlocks deactivated, the front end still shows the saved HTML, because WordPress renders the stored markup of a block whose type is not registered. The style element is gone, so the section background, the heading colour and the button styling disappear:
<div class="entry-content" itemprop="text">
<section class="gb-element-lp01hero">
<h1 class="gb-text gb-text-lp01head">Spring 2027 catalogue</h1>
<p class="gb-text">Twelve new titles from Lumen Press, Lumen Kids and Lumen Noir.</p>
<a class="gb-text gb-text-lp01link" href="/books/">Browse the catalogue</a>
</section>
In the editor, each such block appears as an unsupported block with the option to keep it as HTML. The same applies to
Kadence Blocks (kadence/* names) and to any block plugin. The leftover is tidier than an editor-replacing builder’s,
but the page still has to be rebuilt with core blocks to be editable and styled again.
Shortcode-based builders and themes
Older builders, and some theme "elements", store layouts as nested shortcodes in post_content. When the plugin or
theme that registers them is gone, WordPress prints unknown shortcodes literally, so pages fill with bracketed tags.
The free Elementor version tested here stored no shortcodes in content, but a site may still contain them from add-ons
or older tools; search for them before switching anything off (see the checklist below).
Multipurpose themes
Switching away from a multipurpose theme leaves the content intact, since posts are ordinary blocks or HTML. What goes
is the presentation configured in the theme: the Customizer-built header and footer, layout options, colours and fonts
stored in astra-settings or theme_mods_<slug>, page-level meta such as "disable title" or "full-width" switches, and
any content the paid add-on generated (custom layouts, hooks, mega menus). WordPress keeps each theme’s mods in its own
theme_mods_<slug> option, so switching back restores them; the new theme ignores them.
Front-end weight
The measurements below come from one uncached request per page, counting <link rel="stylesheet"> and
<script src> tags and adding up the uncompressed size of the files served by the site itself. External files (Google
Fonts) are counted as tags only. Numbers depend on settings and versions; the method is the useful part.
URL=https://lumenpress.test/spring-elementor/
curl -s "$URL" | grep -oE "<link[^>]+rel=.stylesheet[^>]*>" | grep -oE "id=['\"][^'\"]+"
curl -s "$URL" | grep -oE "<script[^>]+src=['\"][^'\"]+" | wc -l
| Theme and plugin, page | HTML | Stylesheets (local bytes) | Scripts (local bytes) | Inline <style> |
|---|---|---|---|---|
Twenty Twenty-Five, no plugins, core blocks |
73,000 |
0 (0) |
1 (3,033) |
56,781 |
GeneratePress, no plugins, core blocks |
51,919 |
1 (19,512) |
1 (7,333) |
37,030 |
GeneratePress + GenerateBlocks, GenerateBlocks page |
47,335 |
1 (19,512) |
1 (7,333) |
32,627 |
Kadence, no plugins, core blocks |
54,363 |
4 (107,592) |
1 (22,428) |
37,270 |
Astra, no plugins, core blocks |
105,753 |
1 (44,905) |
1 (26,933) |
88,102 |
Astra + Elementor active, core-blocks page |
98,378 |
2 (185,734) |
1 (26,933) |
79,884 |
Astra + Elementor, Elementor page |
108,330 |
9, 2 of them Google Fonts (105,819) |
7 (259,948) |
83,584 |
What the table shows for these versions:
-
Twenty Twenty-Five loads no stylesheet file: core inlines the used block styles and global styles, and the only script is the Navigation block’s view module. Lean multipurpose themes add one small stylesheet and script; a block-based builder adds only inline CSS.
-
The Elementor page loads jQuery, jQuery Migrate, jQuery UI Core and three Elementor bundles (about 260 KB of JavaScript before compression) plus kit, post and widget stylesheets, and the default kit loads Roboto and Roboto Slab from
fonts.googleapis.com, which sends visitors' IP addresses to Google (Typography and Fonts). -
With Elementor merely active, a core-blocks page loaded the whole
wp-block-librarystylesheet (about 140 KB).
Byte counts are only a proxy; field Core Web Vitals, caching and compression decide what visitors feel (Performance and Caching).
Block themes compared
| Concern | Block theme with core blocks | Block-based builder | Editor-replacing builder / multipurpose theme |
|---|---|---|---|
Performance |
Per-block CSS inlined; little or no JavaScript |
Small: generated CSS per page, few files |
Builder: several CSS and JS files, often jQuery and web fonts; multipurpose themes vary from one small file to many |
Lock-in |
None beyond the theme’s templates and patterns; content is portable |
Content readable, styles and editing tied to the plugin |
Builder: layout in private meta; theme: header, footer and options tied to the theme |
Markup left behind on deactivation |
Nothing (core blocks are always registered) |
Unsupported blocks with plain HTML and class names |
Plain HTML in |
Editing experience |
The block editor and Site Editor, consistent across sites; design limited to what the theme exposes in |
Block editor with many extra controls; risk of inconsistent one-off styling |
A second editing environment with its own UI, revisions and permissions; very flexible per page |
Cost |
Free (core and directory themes); development time for custom themes |
Free plugin; paid add-on for advanced blocks |
Free tier; yearly licences for Pro add-ons, and expired licences stop updates |
Builders remain a reasonable choice when non-technical editors need layout freedom on many unique landing pages and the site accepts the dependency. A block theme suits sites with a consistent design system, like Lumen Press, where editors fill content into patterns rather than design pages.
Evaluating a commercial theme or builder
Use the general vetting steps in Choosing and Managing Plugins and Themes, plus these checks specific to design products:
-
Licence. The PHP is GPL; what is sold is updates and support. A lapsed licence usually stops security fixes, so budget renewals for the life of the site, and list the features that exist only in the paid tier.
-
Exit test. On staging, build a representative page, deactivate the product and inspect front end, editor and database as shown above.
-
Plugin territory. Directory themes must leave post types, shortcodes and blocks to plugins; a theme sold elsewhere may not, which ties content to the theme.
-
Weight and privacy. Measure a typical page, including pages that do not use the product, and look for external requests (fonts, icons, licence checks) that cannot be self-hosted or disabled.
-
Accessibility. Check heading order, landmarks, focus styles and keyboard support in generated menus, sliders and tabs (Accessibility).
-
Compatibility. Compare the listing’s "Requires WordPress" and "Requires PHP" values and release history with core releases; GeneratePress and Kadence list PHP 7.4 and Astra PHP 5.3, so none of them requires PHP 8.2.
-
Starter sites. Importers add pages, images, menus, options and sometimes plugins in bulk; import on staging and keep only what is used.
Source: Themes Team Handbook: Required
Migrating away
Moving Lumen Press from a builder or multipurpose theme to the lumen block theme is a content project as much as a
code one. The theme side (Customizer settings to theme.json, menus to Navigation, widgets to patterns) is covered in
Hybrid Themes and Migration to Block Themes. For
the builder content:
-
Back up files and database, and work on staging (Backups and Disaster Recovery).
-
Inventory the pages that depend on the builder:
wp post list --post_type=any --meta_key=_elementor_edit_mode --meta_value=builder --fields=ID,post_type,post_titleSource: WP-CLI Commands: wp post list
ID post_type post_title 8 page Spring catalogue (Elementor)For block-based builders, search
post_contentfor their block names (wp db search 'wp:generateblocks/'or'wp:kadence/'); for shortcode tools, search for their shortcode names. -
Capture the design system: colours, fonts and spacing from the builder kit or theme options become presets in the new theme’s
theme.json(theme.json Settings). -
Rebuild repeated layouts as patterns in the block theme (Theme Patterns), and headers and footers as template parts.
-
Convert each page. With the builder deactivated, open the page in the block editor, use "Convert to blocks" on the Classic block, then replace the result with a pattern and the real content. For block-based builders, replace each unsupported block with core blocks. Compare old and new pages side by side.
-
Deactivate and delete the builder and the multipurpose theme (and their paid add-ons), then clean the leftover data after another backup. For Elementor, as tested on a second test site with one builder page (table prefix
wp_; use the site’s own; the options count includes Elementor’s transients):wp db export before-cleanup.sql wp db query "DELETE FROM wp_postmeta WHERE meta_key LIKE '\\_elementor%'" wp db query "DELETE FROM wp_options WHERE option_name LIKE 'elementor\\_%' OR option_name LIKE '\\_elementor\\_%' OR option_name LIKE '\\_transient%elementor%'" wp post delete $(wp post list --post_type=elementor_library --format=ids) --forceSource: WP-CLI Commands: wp post delete
Success: Exported to 'before-cleanup.sql'. Success: Query succeeded. Rows affected: 10 Success: Query succeeded. Rows affected: 13 Success: Deleted post 4.Remove the plugin’s upload folder (
wp-content/uploads/elementor/) and the old theme’stheme_mods_<slug>option once the new theme is live. -
Check and re-measure: redirect changed URLs, look for literal shortcodes, and re-run performance, accessibility and visual checks on the converted pages.
Data formats change between product versions; inspect the actual meta keys and options (wp post meta list,
wp option list --search='<prefix>*') before deleting anything.
Pitfalls and corrections to older books
-
Page builders are not required to design a WordPress site. Older books (Ultimate WordPress Handbook in particular, built around GeneratePress and GenerateBlocks with the Customizer) teach design through a commercial theme and a builder, and describe full site editing as still maturing. Block themes and the Site Editor have been the core approach since 5.9 and are the default of every bundled theme since Twenty Twenty-Two; builders are an optional ecosystem choice.
-
Themes do not generally need PHP 8.2 or newer, as one older book states: GeneratePress and Kadence state PHP 7.4, Astra PHP 5.3, and WordPress 7.1 itself runs on PHP 7.4.
-
Free versus premium is about updates and support, not ownership. Commercial themes and add-ons are GPL; an expired licence typically stops updates, including security fixes. Nulled copies are a security risk.
-
Deactivating or uninstalling a builder does not return a clean page or database, as shown above.