Preview: FormEmbedWizard.php
Size: 16.23 KB
/proc/self/root/home/nshryvcy/radiantskinclinics.org/wp-content/plugins/wpforms-lite/src/Admin/FormEmbedWizard.php
<?php
namespace WPForms\Admin;
use WPForms\Admin\Builder\PreviewDropdownEducationItems;
use WPForms_Builder;
use WP_Post;
/**
* Embed Form in a Page wizard.
*
* @since 1.6.2
*/
class FormEmbedWizard {
/**
* Max search results count of 'Select Page' dropdown.
*
* @since 1.7.9
*
* @var int
*/
const MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT = 20;
/**
* Post statuses of pages in 'Select Page' dropdown.
*
* @since 1.7.9
*
* @var string[]
*/
const POST_STATUSES_OF_DROPDOWN_PAGES = [ 'publish', 'pending' ];
/**
* Initialize class.
*
* @since 1.6.2
*/
public function init() {
// Form Embed Wizard should load only in the Form Builder and on the Edit/Add Page screen.
if (
! wpforms_is_admin_page( 'builder' ) &&
! wpforms_is_admin_ajax() &&
! $this->is_form_embed_page()
) {
return;
}
$this->hooks();
}
/**
* Register hooks.
*
* @since 1.6.2
* @since 1.7.9 Add hook for searching pages in embed wizard via AJAX.
*/
public function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
add_action( 'admin_footer', [ $this, 'output' ] );
add_filter( 'default_title', [ $this, 'embed_page_title' ], 10, 2 );
add_filter( 'default_content', [ $this, 'embed_page_content' ], 10, 2 );
add_action( 'wp_ajax_wpforms_admin_form_embed_wizard_embed_page_url', [ $this, 'get_embed_page_url_ajax' ] );
add_action( 'wp_ajax_wpforms_admin_form_embed_wizard_search_pages_choicesjs', [ $this, 'get_search_result_pages_ajax' ] );
}
/**
* Enqueue assets.
*
* @since 1.6.2
* @since 1.7.9 Add 'underscore' as dependency.
*/
public function enqueues() {
$min = wpforms_get_min_suffix();
if ( $this->is_form_embed_page() && $this->get_meta() && ! $this->is_challenge_active() ) {
wp_enqueue_style(
'wpforms-admin-form-embed-wizard',
WPFORMS_PLUGIN_URL . "assets/css/form-embed-wizard{$min}.css",
[],
WPFORMS_VERSION
);
wp_enqueue_style(
'tooltipster',
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.css',
null,
'4.2.6'
);
wp_enqueue_script(
'tooltipster',
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.js',
[ 'jquery' ],
'4.2.6',
true
);
}
// In the Form Builder the education cards delegate their "open preview"
// and "jump to settings section" actions to the Preview dropdown module,
// so we declare it as an explicit dependency there.
$deps = [ 'jquery', 'underscore' ];
if ( wpforms_is_admin_page( 'builder' ) ) {
$deps[] = 'wpforms-builder-preview-dropdown';
}
wp_enqueue_script(
'wpforms-admin-form-embed-wizard',
WPFORMS_PLUGIN_URL . "assets/js/admin/form-embed-wizard{$min}.js",
$deps,
WPFORMS_VERSION,
false
);
wp_localize_script(
'wpforms-admin-form-embed-wizard',
'wpforms_admin_form_embed_wizard',
[
'nonce' => wp_create_nonce( 'wpforms_admin_form_embed_wizard_nonce' ),
'is_edit_page' => (int) $this->is_form_embed_page( 'edit' ),
'i18n' => [
'add_to_page' => __( 'Add to Page', 'wpforms-lite' ),
'create_page' => __( 'Create Page', 'wpforms-lite' ),
],
]
);
}
/**
* Output HTML.
*
* @since 1.6.2
*/
public function output() {
// We don't need to output tooltip if Challenge is active.
if ( $this->is_form_embed_page() && $this->is_challenge_active() ) {
$this->delete_meta();
return;
}
// We don't need to output tooltip if it's not an embed flow.
if ( $this->is_form_embed_page() && ! $this->get_meta() ) {
return;
}
$template = $this->is_form_embed_page() ? 'admin/form-embed-wizard/tooltip' : 'admin/form-embed-wizard/popup';
$args = [];
if ( ! $this->is_form_embed_page() ) {
$args['user_can_edit_pages'] = current_user_can( 'edit_pages' );
$args['dropdown_pages'] = $this->get_select_dropdown_pages_html();
$args['education_items'] = $this->get_education_items();
$args['is_lite'] = ! wpforms()->is_pro();
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo wpforms_render( $template, $args );
$this->delete_meta();
}
/**
* Check if Challenge is active.
*
* @since 1.6.4
*
* @return boolean
*/
public function is_challenge_active() {
static $challenge_active = null;
if ( $challenge_active === null ) {
$challenge = wpforms()->obj( 'challenge' );
$challenge_active = method_exists( $challenge, 'challenge_active' ) ? $challenge->challenge_active() : false;
}
return $challenge_active;
}
/**
* Check if the current page is a form embed page.
*
* @since 1.6.2
*
* @param string $type Type of the embed page to check. Can be '', 'add' or 'edit'. By default is empty string.
*
* @return boolean
*/
public function is_form_embed_page( $type = '' ) {
global $pagenow;
$type = $type === 'add' || $type === 'edit' ? $type : '';
if (
$pagenow !== 'post.php' &&
$pagenow !== 'post-new.php'
) {
return false;
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$post_id = empty( $_GET['post'] ) ? 0 : (int) $_GET['post'];
$post_type = empty( $_GET['post_type'] ) ? '' : sanitize_key( $_GET['post_type'] );
$action = empty( $_GET['action'] ) ? 'add' : sanitize_key( $_GET['action'] );
// phpcs:enable
if ( $pagenow === 'post-new.php' &&
( empty( $post_type ) || $post_type !== 'page' )
) {
return false;
}
if (
$pagenow === 'post.php' &&
( empty( $post_id ) || get_post_type( $post_id ) !== 'page' )
) {
return false;
}
$meta = $this->get_meta();
$embed_page = ! empty( $meta['embed_page'] ) ? (int) $meta['embed_page'] : 0;
if ( 'add' === $action && 0 === $embed_page && $type !== 'edit' ) {
return true;
}
if ( ! empty( $post_id ) && $embed_page === $post_id && $type !== 'add' ) {
return true;
}
return false;
}
/**
* Set user's embed meta data.
*
* @since 1.6.2
*
* @param array $data Data array to set.
*/
public function set_meta( $data ) {
update_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard', $data );
}
/**
* Get user's embed meta data.
*
* @since 1.6.2
*
* @return array User's embed meta data.
*/
public function get_meta() {
return get_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard', true );
}
/**
* Delete user's embed meta data.
*
* @since 1.6.2
*/
public function delete_meta() {
delete_user_meta( get_current_user_id(), 'wpforms_admin_form_embed_wizard' );
}
/**
* Get embed page URL via AJAX.
*
* @since 1.6.2
*/
public function get_embed_page_url_ajax() {
// Run a security check.
check_admin_referer( 'wpforms_admin_form_embed_wizard_nonce' );
// Check for permissions.
if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
wp_send_json_error( esc_html__( 'You are not allowed to perform this action.', 'wpforms-lite' ) );
}
$page_id = ! empty( $_POST['pageId'] ) ? absint( $_POST['pageId'] ) : 0;
$meta = $this->prepare_meta_data( $page_id );
$this->set_meta( $meta );
// Update challenge option to properly continue challenge on the embed page.
$this->update_challenge_option( $meta );
wp_send_json_success( $meta['url'] );
}
/**
* Prepare meta data for the embed page.
*
* @since 1.9.4
*
* @param int $page_id Page ID.
*
* @return array
*/
private function prepare_meta_data( int $page_id ): array {
if ( ! empty( $page_id ) ) {
$url = get_edit_post_link( $page_id, '' );
$meta = [
'embed_page' => $page_id,
];
} else {
$url = add_query_arg( 'post_type', 'page', admin_url( 'post-new.php' ) );
$meta = [
'embed_page' => 0,
'embed_page_title' => ! empty( $_POST['pageTitle'] ) ? sanitize_text_field( wp_unslash( $_POST['pageTitle'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing
];
}
$meta['form_id'] = ! empty( $_POST['formId'] ) ? absint( $_POST['formId'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$meta['url'] = $url;
return $meta;
}
/**
* Update challenge option to properly continue challenge on the embed page.
*
* @since 1.9.4
*
* @param array $meta Meta data.
*/
private function update_challenge_option( array $meta ): void {
if ( $this->is_challenge_active() ) {
$challenge = wpforms()->obj( 'challenge' );
if ( $challenge && method_exists( $challenge, 'set_challenge_option' ) ) {
$challenge->set_challenge_option( [ 'embed_page' => $meta['embed_page'] ] );
}
}
}
/**
* Set default title for the new page.
*
* @since 1.6.2
*
* @param string $post_title Default post title.
* @param \WP_Post $post Post object.
*
* @return string New default post title.
*/
public function embed_page_title( $post_title, $post ) {
$meta = $this->get_meta();
$this->delete_meta();
return empty( $meta['embed_page_title'] ) ? $post_title : $meta['embed_page_title'];
}
/**
* Embed the form to the new page.
*
* @since 1.6.2
*
* @param string $post_content Default post content.
* @param \WP_Post $post Post object.
*
* @return string Embedding string (shortcode or GB component code).
*/
public function embed_page_content( $post_content, $post ) {
$meta = $this->get_meta();
$form_id = ! empty( $meta['form_id'] ) ? $meta['form_id'] : 0;
$page_id = ! empty( $meta['embed_page'] ) ? $meta['embed_page'] : 0;
if ( ! empty( $page_id ) || empty( $form_id ) ) {
return $post_content;
}
if ( wpforms_is_gutenberg_active() ) {
$pattern = '<!-- wp:wpforms/form-selector {"formId":"%d"} /-->';
} else {
$pattern = '[wpforms id="%d" title="false" description="false"]';
}
return sprintf( $pattern, absint( $form_id ) );
}
/**
* Get product education items shown in the embed wizard card grid.
*
* Reuses the canonical item list from `PreviewDropdownEducationItems`
* and enriches each item with wizard-specific UTM content, demo URL,
* card-body attributes, and (for Lite users) the upgrade URL.
*
* @since 1.10.1
*
* @return array
*/
private function get_education_items(): array {
$items = ( new PreviewDropdownEducationItems( $this->get_current_form() ) )->get_items();
if ( empty( $items ) ) {
return [];
}
// UTM content mapping keyed by item slug.
$utm_map = [
'conversational-forms' => [
'upgrade' => 'Conversational Forms - Upgrade to Pro Link',
'demo' => 'Conversational Forms - Demo Link',
],
'form-pages' => [
'upgrade' => 'Form Pages - Upgrade to Pro Link',
'demo' => 'Form Pages - Demo Link',
],
'lead-forms' => [
'upgrade' => 'Lead Forms - Upgrade to Pro Link',
'demo' => 'Lead Forms - Demo Link',
],
];
$is_lite = ! wpforms()->is_pro();
foreach ( $items as &$item ) {
$slug_utm = $utm_map[ $item['slug'] ] ?? [];
// Override UTM medium and content for the embed wizard context.
$item['utm_medium'] = 'Builder Embed Modal';
$item['utm_content'] = $slug_utm['upgrade'] ?? $item['utm_content'];
$item['demo_utm_content'] = $slug_utm['demo'] ?? ( $item['demo_utm_content'] ?? $item['utm_content'] );
$item['demo_url'] = PreviewDropdownEducationItems::get_demo_url( $item );
$item['button_attrs'] = $this->get_education_item_attrs( $item, $is_lite );
if ( $is_lite ) {
$item['upgrade_url'] = wpforms_admin_upgrade_link( 'Builder Embed Modal', $item['utm_content'] );
}
}
unset( $item );
return $items;
}
/**
* Build the CSS class and data attributes for an education card body.
*
* Mirrors the Preview dropdown's `print_preview_dropdown_item()` logic so
* clicks on the card body are handled by the same JS flows already wired
* to the Preview dropdown: education upgrade modal (Lite), Addons Required
* modal (Pro without addon), or "active addon" preview handler (Pro with
* addon installed and active).
*
* @since 1.10.1
*
* @param array $item Education item.
* @param bool $is_lite Whether the current user is on Lite.
*
* @return array {
* Card body rendering data.
*
* @type string $class CSS class for the card body.
* @type array $data Associative array of `data-*` attributes (name => value).
* }
*/
private function get_education_item_attrs( array $item, bool $is_lite ): array {
if ( $is_lite ) {
// Lite user — card click opens the pricing page directly,
// bypassing the standard education upgrade modal.
return [
'class' => 'wpforms-admin-form-embed-wizard-card-education-lite',
'data' => [
'name' => $item['label'],
'utm-content' => $item['utm_content'],
'upgrade-url' => wpforms_admin_upgrade_link( 'Builder Embed Modal', $item['utm_content'] ),
],
];
}
$addon_slug = $item['addon_slug'] ?? '';
if ( PreviewDropdownEducationItems::is_addon_active( $addon_slug ) ) {
// Addon is installed and active — open preview URL in a new tab,
// scoped to the addon section via the `section` query param.
$preview_url = $item['preview_url'] ?? '';
return [
'class' => 'wpforms-admin-form-embed-wizard-card-education-active',
'data' => [
'section' => $item['section'] ?? '',
'toggle-id' => $item['toggle_id'] ?? '',
'preview-url' => $preview_url,
],
];
}
// Pro user without the addon installed or active — open the
// Addons Required modal (same handler as the Preview dropdown).
return [
'class' => 'wpforms-addons-required-trigger',
'data' => [
'license' => 'pro',
'name' => $item['label'],
'utm-content' => $item['utm_content'],
'demo-url' => $item['demo_url'],
'addon-slug' => $addon_slug,
],
];
}
/**
* Resolve the current builder form from the Builder singleton.
*
* @since 1.10.1
*
* @return WP_Post|null
*/
private function get_current_form(): ?WP_Post {
if ( ! class_exists( WPForms_Builder::class ) ) {
return null;
}
$form = WPForms_Builder::instance()->form ?? null;
return $form instanceof WP_Post ? $form : null;
}
/**
* Generate select with pages which are available to edit for current user.
*
* @since 1.6.6
* @since 1.7.9 Refactor to use ChoicesJS instead of `wp_dropdown_pages()`.
*
* @return string
*/
private function get_select_dropdown_pages_html() {
$dropdown_pages = wpforms_search_posts(
'',
[
'count' => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
]
);
if ( empty( $dropdown_pages ) ) {
return '';
}
$total_pages = 0;
$wp_count_pages = (array) wp_count_posts( 'page' );
foreach ( $wp_count_pages as $page_status => $pages_count ) {
if ( in_array( $page_status, self::POST_STATUSES_OF_DROPDOWN_PAGES, true ) ) {
$total_pages += $pages_count;
}
}
// Include so we can use `\wpforms_settings_select_callback()`.
require_once WPFORMS_PLUGIN_DIR . 'includes/admin/settings-api.php';
return wpforms_settings_select_callback(
[
'id' => 'form-embed-wizard-choicesjs-select-pages',
'type' => 'select',
'choicesjs' => true,
'options' => wp_list_pluck( $dropdown_pages, 'post_title', 'ID' ),
'data' => [
'use_ajax' => $total_pages > self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
],
]
);
}
/**
* Get search result pages for ChoicesJS via AJAX.
*
* @since 1.7.9
*/
public function get_search_result_pages_ajax() {
// Run a security check.
if ( ! check_ajax_referer( 'wpforms_admin_form_embed_wizard_nonce', false, false ) ) {
wp_send_json_error(
[
'msg' => esc_html__( 'Your session expired. Please reload the builder.', 'wpforms-lite' ),
]
);
}
// Check for permissions.
if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
wp_send_json_error( esc_html__( 'You are not allowed to perform this action.', 'wpforms-lite' ) );
}
if ( ! array_key_exists( 'search', $_GET ) ) {
wp_send_json_error(
[
'msg' => esc_html__( 'Incorrect usage of this operation.', 'wpforms-lite' ),
]
);
}
$result_pages = wpforms_search_pages_for_dropdown(
sanitize_text_field( wp_unslash( $_GET['search'] ) ),
[
'count' => self::MAX_SEARCH_RESULTS_DROPDOWN_PAGES_COUNT,
'post_status' => self::POST_STATUSES_OF_DROPDOWN_PAGES,
]
);
if ( empty( $result_pages ) ) {
wp_send_json_error( [] );
}
wp_send_json_success( $result_pages );
}
}
Directory Contents
Dirs: 15 × Files: 9