Independent add-on: Forms Converter Add-on For HTML Page Publisher is made and supported by Xavier Castaneda. It is not an official HTML Page Publisher add-on, and HTML Page Publisher’s author doesn’t provide support for it. Support: https://github.com/xcast3d/forms-for-html-page-publisher/issues
This add-on is built specifically for the original HTML Page Publisher plugin. HTML Page Publisher remains responsible for uploading, storing, versioning, and serving the static landing pages; this add-on supplies form detection, conversion, and rendering. It requires HTML Page Publisher 1.5.2 or later and does not replace it.
HTML Page Publisher publishes uploaded static landing pages as-is, outside the theme. Landing pages generated by AI tools or page builders usually include a <form> that doesn’t submit anywhere. This add-on converts those static forms into working Gravity Forms, Contact Form 7 or WPForms forms (see Detect Forms below), and lets you place any existing form in a page with an HTML comment placeholder:
<!-- form:gravity:12 --> – Gravity Forms
<!-- form:cf7:34 --> – Contact Form 7
<!-- form:wpforms:56 --> – WPForms (Lite or Pro)
Optional flags (both default to false, since landing pages usually have their own heading):
<!-- form:wpforms:56 title=true description=true -->
The older <!-- gravity-form:12 --> syntax keeps working.
<!-- form:cf7:34 styles=page button-class="btn btn-primary" -->
With styles=page, the form plugin’s visual theme is turned off and the landing page’s own CSS styles the form:
gform_disable_css), plain markup without Orbital variables, no “* indicates required fields” note.<input> becomes an equivalent <button>, so button rules written for the original page apply.button-class is added to the submit button; class and id (optional) go on the rendered form and a wrapper.:where(), so any rule in the page wins.Without styles=page, forms use the form plugin’s own theme.
Converted forms use styles=page by default (filter ffhpp_default_styles). The original <form> becomes a <div> with the same class, id and other presentational attributes, and anything inside the form before the first field (a heading, intro text) or after the button stays in place around the placeholder:
<div id="signup" class="signup-form"><h2>Tell us about your project</h2><!-- form:cf7:34 styles=page button-class="btn btn-primary" --></div>
So rules like .signup-form, .signup-form input, .signup-form label, #signup … and .btn-primary keep working. Textarea rows and the submit button text carry over.
What it does:
Requires HTML Page Publisher 1.5.2 or later and at least one of: Gravity Forms (2.9+; tested with 3.2.0), Contact Form 7 (tested with 6.2.3), WPForms Lite/Pro (tested with Lite 2.0.3).
AI-generated pages often ship a <form> with no working backend. HTML Pages Detect Forms finds them:
<form>…</form> in the page with its placeholder. The rest of the page is untouched.Field mapping:
Detected
Gravity Forms
Contact Form 7
WPForms Lite (Pro)
text, search, password
Single Line Text
[text]
Single Line Text
email
Email
[email]
Email
tel
Phone
[tel]
Single Line Text (Phone)
url
Website
[url]
Single Line Text (Website)
number, range
Number
[number]
Numbers
date
Date
[date]
Single Line Text (Date)
hidden
Hidden, filled from the query string
[hidden … default:get]
skipped (Hidden, {query_var})
textarea
Paragraph Text
[textarea]
Paragraph Text
select
Drop Down
[select … first_as_label]
Dropdown
radio group
Radio Buttons
[radio]
Multiple Choice
checkbox group
Checkboxes
[checkbox]
Checkboxes
lone “I agree…” checkbox
Consent
[acceptance]
Checkboxes, one choice, label hidden
A lone checkbox counts as consent when its text mentions agree, consent, accept, privacy, terms, policy or opt-in. Labels come from <label for>, a wrapping <label>, a group’s <legend>, then aria-label, placeholder, title or name. Choice values are kept (Contact Form 7 uses “Text|value” pipes).
Created forms get each plugin’s usual defaults: a confirmation message and an admin email notification. Contact Form 7’s mail body lists every field, with Reply-To set to the first email field.
Converting requires the publisher’s capability plus unfiltered_html (the same check as its HTML editor), and permission to create forms in the chosen plugin (gravityforms_create_form, wpcf7_edit_contact_forms, or WPForms’ create_forms).
Commands live under the publisher’s own wp htmlpp namespace:
wp htmlpp forms plugins – supported form plugins, whether each is active, and its placeholder.wp htmlpp forms detect [<slug>] – raw HTML forms per page (fields, button, where it posts). --format, --fields.wp htmlpp forms convert <slug> --to=<gravity|cf7|wpforms> [--form=<n>|--all] [--styles=page|plugin] [--dry-run] [--porcelain] – convert forms; --dry-run shows the fields, notes and placeholder without changing anything. Run as an administrator (--user=<login>), since form plugins check the current user’s permissions.wp htmlpp forms placeholders [<slug>] [--problems] – every placeholder and whether its form can be shown (ok, form missing, plugin inactive, unknown plugin).Examples:
wp htmlpp forms detect
wp htmlpp forms convert spring-promo --to=cf7 --dry-run
wp htmlpp forms convert spring-promo --to=gravity --all --user=admin
wp htmlpp forms placeholders --problems
Converted forms are titled after the page, with “— form N” (by position in the page) when it has more than one.
Open an issue at https://github.com/xcast3d/forms-for-html-page-publisher/issues with your WordPress, HTML Page Publisher and form plugin versions. For problems with HTML Page Publisher itself (uploading or publishing pages), use its support forum: https://wordpress.org/support/plugin/html-page-publisher/
Uses only HTML Page Publisher’s public hooks and page service (version 1.5.2 or later):
htmlpp_page_html – replace placeholders and inject assets.htmlpp_before_serve – route a form submission before the page is served.htmlpp_page_created / htmlpp_page_updated – flag pages that contain HTML forms.htmlpp_page_meta_defaults – register the per-page form count (html_forms), read and written through htmlpp()->pages.htmlpp_serve_priority – serve pages after form plugins have initialised (see below).htmlpp()->pages – read pages and their HTML, and save a converted page with a version backup (update_html()).Two adjustments, both needed because pages are served during init:
init priority 0 by default, before form plugins initialise (init, 10). This add-on raises that to priority 20 through htmlpp_serve_priority (filterable with ffhpp_serve_priority). Pages are still served before WordPress’s main query runs.wp_enqueue_scripts, which never fires on these pages. When one of their forms is on a page, the add-on runs that action once, keeps the registrations, and discards whatever the theme or other plugins enqueued.Extend FFHPP_Adapter (form_exists, render, create_form, delete_form, edit_url, can_create, and optionally submission routing and conversion notes) and add an instance with the ffhpp_adapters filter. Its id() becomes the placeholder key: <!-- form:{id}:{form ID} -->.
ffhpp_adapters (FFHPP_Adapter[]) – form plugin adapters, in order of preference.ffhpp_serve_priority (int, default 20) – init priority pages are served at.ffhpp_form_markup (string $markup, string $adapter, int $form_id, bool $preview) – rendered form HTML before it replaces the placeholder.ffhpp_consent_pattern (string $pattern) – regex that marks a lone checkbox as a consent field.ffhpp_default_styles (string ‘page’|’plugin’, FFHPP_Adapter $adapter, array $form) – styling mode written into converted placeholders.Filters and actions used the htmlpp_forms_ prefix before 0.7.0 (for example htmlpp_forms_adapters). The old names still work in 0.7.0 with a deprecation notice when WP_DEBUG is on, and will be removed in the next release.
ffhpp_form_converted (string $adapter, int $form_id, string $slug, array $form) – after an HTML form was converted.init callbacks (priority < 20), slightly later than before..signup-form input, #signup label) keep working; rules that depend on the original structure (.signup-form > label, sibling selectors, grid placement of direct children, classes on individual fields) do not, and form.signup-form no longer matches (it’s a <div> now). Page JavaScript bound to the old form stops working.label rules also reach the labels of radio and checkbox choices, which may make them bolder than in the original.<form> inside a <script> string or HTML comment would also be listed.