Skip to content

Commit ca5d0f2

Browse files
enejbmatticbot
authored andcommitted
Forms: add form preview functionality (#46935)
* Forms: add form preview functionality Add preview functionality to Jetpack Forms allowing admins/editors to preview forms at a temporary nonce-based URL. Forms render within the site's page template with submissions disabled in preview mode. - Add Form_Preview class to handle preview rendering - Add REST endpoint for generating preview URLs - Add preview action to forms dashboard list - Add preview menu item to form editor - Block form submissions in preview mode (PHP and JS) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update projects/packages/forms/src/contact-form/class-form-preview.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Forms: fix form preview rendering - Use the form's ID for the fake post context instead of 0, which was causing the form ID validation to fail (since '0' is falsy in PHP) - Add preview mode exceptions to the module and frontend checks in gutenblock_render_form() so forms render during preview - Add jetpack_is_frontend filter to ensure proper frontend detection - Set is_404 and is_feed to false in the query context Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Forms: add tests for Form_Preview class Add comprehensive unit tests for the Form_Preview functionality: - Test hook registration via init() - Test query variable registration - Test preview mode state management - Test preview URL generation for various scenarios - Test access verification (logged out, no capability, invalid nonce, valid) - Test jetpack_is_frontend filter behavior - Test handling of draft forms * Forms: use registerPlugin for preview menu item Switch from registerJetpackPlugin to WordPress core's registerPlugin for the form preview menu item. This ensures the plugin renders correctly in the form editor context. Also adds loading state to show "Opening preview…" feedback while the preview URL is being fetched. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Use autosave for form preview Ensure previews reflect the latest unsaved edits by using the editor autosave. In PHP, Form_Preview now checks wp_get_post_autosave and uses the autosave post if it's newer than the saved form. In the editor plugin, the preview button reads editor dirty/autosaveable state and calls the core/editor autosave before requesting the preview URL; the button text and hook deps were updated accordingly. Files changed: class-form-preview.php, preview-button.tsx. * Forms: add preview action to wp-build dashboard Add the "Preview" action to the Forms list in the wp-build dashboard (routes/forms/stage.tsx), matching the functionality already present in the React Router dashboard. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Addressing issue. Improve form preview UX and error handling Clarify changelog and refine preview behavior and UI. Stop returning a WP_Error in preview submission handler (now returns early) and surface the preview-mode message to client-side strings. Make preview CSS enqueuing robust by using filemtime when available with a fallback version, and update CSS to use margin-block-end. In the dashboard and editor preview code, add notices integration to show a snackbar error when preview URL generation fails and include the notice dispatcher in hook deps. * Improve Form_Preview null-safety and versioning Use a boolean true for current_time GMT flag, add nullable WP_Post typing and an early return to render_form_preview_content to avoid errors when no form is provided, and switch CSS versioning to the package PACKAGE_VERSION constant for accurate asset versioning. * Remove redundant setAccessible calls in test Remove ReflectionProperty::setAccessible(true) calls from Form_Preview_Test methods. These calls were unnecessary for setting the static property and can cause issues with newer PHP versions where setAccessible is deprecated, so the tests are simplified and made more compatible. * Refactor Form_Preview tests and assertions Clean up and simplify Form_Preview unit tests: rename variables (editor/subscriber IDs), create users with randomized logins/emails, and streamline post type registration and test form content. Remove reflection-based preview-mode helpers and consolidate setup/teardown to rely on BaseTestCase. Update and rename tests to focus on generate_preview_url, verify_preview_access, maybe_render_preview, and draft preview behavior, adjusting assertions accordingly and removing the data provider import and related invalid-ID test matrix. * simplify the error. * minor text copy * fix ternary on i18n message --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Douglas <douglas.henri@automattic.com> Committed via a GitHub action: https://github.com/Automattic/jetpack/actions/runs/21693256612 Upstream-Ref: Automattic/jetpack@54dcce3
1 parent 7c278a7 commit ca5d0f2

24 files changed

Lines changed: 637 additions & 22 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This is an alpha version! The changes listed here are not final.
1212
### Added
1313
- Contact Form: add shortcode transform support for synced form references.
1414
- Dashboard: update header tab counts.
15+
- Forms: add preview functionality allowing users with edit permissions to preview forms at a temporary nonce-based URL.
1516
- Forms: add single form view to wp-build dashboard.
1617
- Response inspector: display star rating icons for rating field submissions.
1718

build/routes/forms/content.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ var require_element = __commonJS({
5656
}
5757
});
5858

59+
// package-external:@wordpress/api-fetch
60+
var require_api_fetch = __commonJS({
61+
"package-external:@wordpress/api-fetch"(exports, module) {
62+
module.exports = window.wp.apiFetch;
63+
}
64+
});
65+
5966
// package-external:@wordpress/data
6067
var require_data = __commonJS({
6168
"package-external:@wordpress/data"(exports, module) {
@@ -1565,13 +1572,6 @@ var require_events = __commonJS({
15651572
}
15661573
});
15671574

1568-
// package-external:@wordpress/api-fetch
1569-
var require_api_fetch = __commonJS({
1570-
"package-external:@wordpress/api-fetch"(exports, module) {
1571-
module.exports = window.wp.apiFetch;
1572-
}
1573-
});
1574-
15751575
// ../../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js
15761576
var require_constants = __commonJS({
15771577
"../../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js"(exports, module) {
@@ -3717,6 +3717,7 @@ Page.SidebarToggleFill = SidebarToggleFill;
37173717
var page_default = Page;
37183718

37193719
// routes/forms/stage.tsx
3720+
var import_api_fetch9 = __toESM(require_api_fetch());
37203721
var import_components71 = __toESM(require_components());
37213722
var import_data19 = __toESM(require_data());
37223723

@@ -27017,6 +27018,26 @@ function StageInner() {
2701727018
const url = new URL(editUrl, window.location.origin);
2701827019
window.location.href = url.toString();
2701927020
}
27021+
},
27022+
{
27023+
id: "preview-form",
27024+
isPrimary: false,
27025+
label: (0, import_i18n74.__)("Preview", "jetpack-forms"),
27026+
supportsBulk: false,
27027+
async callback(items) {
27028+
const [item] = items;
27029+
if (!item) {
27030+
return;
27031+
}
27032+
try {
27033+
const response = await (0, import_api_fetch9.default)({
27034+
path: `/wp/v2/jetpack-forms/${item.id}/preview-url`
27035+
});
27036+
window.open(response.preview_url, "_blank");
27037+
} catch (error2) {
27038+
console.error("Failed to get preview URL:", error2);
27039+
}
27040+
}
2702027041
}
2702127042
];
2702227043
if (isViewingTrash) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url', 'wp-warning'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '2df27e187af1feebe2b6');
1+
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url', 'wp-warning'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '0468c7c2847b6cdbe1b6');

build/routes/forms/content.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/contact-form/css/form-preview.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/contact-form/css/form-preview.rtl.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'ccf5e61b09fff90c9f70');
1+
<?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '7a589358421630f7da9c');

dist/dashboard/jetpack-forms-dashboard.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('jetpack-script-data', 'lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'dfd5653d70a98d0d435d');
1+
<?php return array('dependencies' => array('jetpack-script-data', 'lodash', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'f0c4eaedd47b36c77c6c');

dist/form-editor/jetpack-form-editor.js

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)