View file File name : FormSelector.php Content :<?php namespace WPForms\Integrations\Gutenberg; use WPForms\Frontend\CSSVars; use WPForms\Integrations\IntegrationInterface; use WPForms\Admin\Education\StringsTrait; use WP_Error; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement use WP_REST_Response; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement /** * Form Selector Gutenberg block with live preview. * * @since 1.4.8 */ abstract class FormSelector implements IntegrationInterface { use StringsTrait; /** * Default attributes. * * @since 1.8.1 * * @var array */ const DEFAULT_ATTRIBUTES = [ 'formId' => '', 'displayTitle' => false, 'displayDesc' => false, 'theme' => 'default', 'themeName' => '', 'fieldSize' => 'medium', 'backgroundImage' => CSSVars::ROOT_VARS['background-image'], 'backgroundPosition' => CSSVars::ROOT_VARS['background-position'], 'backgroundRepeat' => CSSVars::ROOT_VARS['background-repeat'], 'backgroundSizeMode' => CSSVars::ROOT_VARS['background-size'], 'backgroundSize' => CSSVars::ROOT_VARS['background-size'], 'backgroundWidth' => CSSVars::ROOT_VARS['background-width'], 'backgroundHeight' => CSSVars::ROOT_VARS['background-height'], 'backgroundUrl' => CSSVars::ROOT_VARS['background-url'], 'backgroundColor' => CSSVars::ROOT_VARS['background-color'], 'fieldBorderRadius' => CSSVars::ROOT_VARS['field-border-radius'], 'fieldBorderStyle' => CSSVars::ROOT_VARS['field-border-style'], 'fieldBorderSize' => CSSVars::ROOT_VARS['field-border-size'], 'fieldBackgroundColor' => CSSVars::ROOT_VARS['field-background-color'], 'fieldBorderColor' => CSSVars::ROOT_VARS['field-border-color'], 'fieldTextColor' => CSSVars::ROOT_VARS['field-text-color'], 'fieldMenuColor' => CSSVars::ROOT_VARS['field-menu-color'], 'labelSize' => 'medium', 'labelColor' => CSSVars::ROOT_VARS['label-color'], 'labelSublabelColor' => CSSVars::ROOT_VARS['label-sublabel-color'], 'labelErrorColor' => CSSVars::ROOT_VARS['label-error-color'], 'buttonSize' => 'medium', 'buttonBorderStyle' => CSSVars::ROOT_VARS['button-border-style'], 'buttonBorderSize' => CSSVars::ROOT_VARS['button-border-size'], 'buttonBorderRadius' => CSSVars::ROOT_VARS['button-border-radius'], 'buttonBackgroundColor' => CSSVars::ROOT_VARS['button-background-color'], 'buttonTextColor' => CSSVars::ROOT_VARS['button-text-color'], 'buttonBorderColor' => CSSVars::ROOT_VARS['button-border-color'], 'pageBreakColor' => CSSVars::ROOT_VARS['page-break-color'], 'containerPadding' => CSSVars::ROOT_VARS['container-padding'], 'containerBorderStyle' => CSSVars::ROOT_VARS['container-border-style'], 'containerBorderWidth' => CSSVars::ROOT_VARS['container-border-width'], 'containerBorderColor' => CSSVars::ROOT_VARS['container-border-color'], 'containerBorderRadius' => CSSVars::ROOT_VARS['container-border-radius'], 'containerShadowSize' => CSSVars::CONTAINER_SHADOW_SIZE['none']['box-shadow'], 'customCss' => '', 'copyPasteJsonValue' => '', ]; /** * Rest API class instance. * * @since 1.8.8 * * @var RestApi */ protected $rest_api_obj; /** * Rest API class instance. * * @since 1.8.8 * * @var ThemesData */ protected $themes_data_obj; /** * Render engine. * * @since 1.8.1 * * @var string */ protected $render_engine; /** * Disabled CSS setting. * * @since 1.8.1 * * @var integer */ protected $disable_css_setting; /** * Instance of CSSVars class. * * @since 1.8.1 * * @var CSSVars */ private $css_vars_obj; /** * Callbacks registered for wpforms_frontend_container_class filter. * * @since 1.7.5 * * @var array */ private $callbacks = []; /** * Currently displayed form Id. * * @since 1.8.8 * * @var string|int */ private $current_form_id = 0; /** * Indicate if current integration is allowed to load. * * @since 1.4.8 * * @return bool */ public function allow_load(): bool { return function_exists( 'register_block_type' ); } /** * Load an integration. * * @since 1.4.8 */ public function load() { $this->render_engine = wpforms_get_render_engine(); $this->disable_css_setting = (int) wpforms_setting( 'disable-css', '1' ); $this->css_vars_obj = wpforms()->obj( 'css_vars' ); wpforms()->register_instance( 'formselector_themes_data', $this->themes_data_obj ); $this->hooks(); } /** * Integration hooks. * * @since 1.4.8 */ protected function hooks() { add_action( 'init', [ $this, 'register_block' ] ); add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_block_editor_assets' ] ); add_action( 'wpforms_frontend_output_container_after', [ $this, 'replace_wpforms_frontend_container_class_filter' ] ); add_filter( 'wpforms_frontend_form_action', [ $this, 'form_action_filter' ], 10, 2 ); add_filter( 'wpforms_forms_anti_spam_v3_is_honeypot_enabled', [ $this, 'filter_is_honeypot_enabled' ] ); add_filter( 'wpforms_field_richtext_display_editor_is_media_enabled', [ $this, 'disable_richtext_media' ], 10, 2 ); } /** * Disable honeypot in Gutenberg/Block editor. * * @since 1.9.0 * * @param bool|mixed $is_enabled True if the honeypot is enabled, false otherwise. * * @return bool Whether to disable the honeypot. */ public function filter_is_honeypot_enabled( $is_enabled ): bool { if ( wpforms_is_rest() ) { return false; } return (bool) $is_enabled; } /** * Replace the filter registered for wpforms_frontend_container_class. * * @since 1.7.5 * * @param array $form_data Form data. * * @return void */ public function replace_wpforms_frontend_container_class_filter( $form_data ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks if ( empty( $this->callbacks[ $form_data['id'] ] ) ) { return; } $callback = array_shift( $this->callbacks[ $form_data['id'] ] ); remove_filter( 'wpforms_frontend_container_class', $callback ); if ( ! empty( $this->callbacks[ $form_data['id'] ] ) ) { add_filter( 'wpforms_frontend_container_class', reset( $this->callbacks[ $form_data['id'] ] ), 10, 2 ); } } /** * Register WPForms Gutenberg block on the backend. * * @since 1.4.8 */ public function register_block() { $attributes = [ 'clientId' => [ 'type' => 'string', ], 'formId' => [ 'type' => 'string', ], 'displayTitle' => [ 'type' => 'boolean', ], 'displayDesc' => [ 'type' => 'boolean', ], 'className' => [ 'type' => 'string', ], 'theme' => [ 'type' => 'string', ], 'themeName' => [ 'type' => 'string', ], 'fieldSize' => [ 'type' => 'string', ], 'fieldBorderRadius' => [ 'type' => 'string', ], 'fieldBorderStyle' => [ 'type' => 'string', ], 'fieldBorderSize' => [ 'type' => 'string', ], 'fieldBackgroundColor' => [ 'type' => 'string', ], 'fieldBorderColor' => [ 'type' => 'string', ], 'fieldTextColor' => [ 'type' => 'string', ], 'fieldMenuColor' => [ 'type' => 'string', ], 'labelSize' => [ 'type' => 'string', ], 'labelColor' => [ 'type' => 'string', ], 'labelSublabelColor' => [ 'type' => 'string', ], 'labelErrorColor' => [ 'type' => 'string', ], 'buttonSize' => [ 'type' => 'string', ], 'buttonBorderStyle' => [ 'type' => 'string', ], 'buttonBorderSize' => [ 'type' => 'string', ], 'buttonBorderRadius' => [ 'type' => 'string', ], 'buttonBackgroundColor' => [ 'type' => 'string', ], 'buttonBorderColor' => [ 'type' => 'string', ], 'buttonTextColor' => [ 'type' => 'string', ], 'pageBreakColor' => [ 'type' => 'string', ], 'backgroundImage' => [ 'type' => 'string', ], 'backgroundPosition' => [ 'type' => 'string', ], 'backgroundRepeat' => [ 'type' => 'string', ], 'backgroundSizeMode' => [ 'type' => 'string', ], 'backgroundSize' => [ 'type' => 'string', ], 'backgroundWidth' => [ 'type' => 'string', ], 'backgroundHeight' => [ 'type' => 'string', ], 'backgroundUrl' => [ 'type' => 'string', ], 'backgroundColor' => [ 'type' => 'string', ], 'containerPadding' => [ 'type' => 'string', ], 'containerBorderStyle' => [ 'type' => 'string', ], 'containerBorderWidth' => [ 'type' => 'string', ], 'containerBorderColor' => [ 'type' => 'string', ], 'containerBorderRadius' => [ 'type' => 'string', ], 'containerShadowSize' => [ 'type' => 'string', ], 'customCss' => [ 'type' => 'string', ], 'copyPasteJsonValue' => [ 'type' => 'string', ], ]; $this->register_styles(); register_block_type( 'wpforms/form-selector', [ /** * Modify WPForms block attributes. * * @since 1.5.8.2 * * @param array $attributes Attributes. */ 'attributes' => apply_filters( 'wpforms_gutenberg_form_selector_attributes', $attributes ), // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName 'style' => 'wpforms-gutenberg-form-selector', 'editor_style' => 'wpforms-integrations', 'render_callback' => [ $this, 'get_form_html' ], ] ); } /** * Register WPForms Gutenberg block styles. * * @since 1.7.4.2 */ protected function register_styles() { if ( ! is_admin() ) { return; } $min = wpforms_get_min_suffix(); wp_register_style( 'wpforms-integrations', WPFORMS_PLUGIN_URL . "assets/css/admin-integrations{$min}.css", [ 'dashicons' ], WPFORMS_VERSION ); if ( $this->disable_css_setting === 3 ) { return; } $css_file = $this->disable_css_setting === 2 ? 'base' : 'full'; wp_register_style( 'wpforms-gutenberg-form-selector', WPFORMS_PLUGIN_URL . "assets/css/frontend/{$this->render_engine}/wpforms-{$css_file}{$min}.css", [ 'wp-edit-blocks', 'wpforms-integrations' ], WPFORMS_VERSION ); } /** * Load WPForms Gutenberg block scripts. * * @since 1.4.8 */ public function enqueue_block_editor_assets() { $min = wpforms_get_min_suffix(); wp_enqueue_style( 'wpforms-integrations' ); wp_set_script_translations( 'wpforms-gutenberg-form-selector', 'wpforms-lite' ); // jQuery.Confirm Reloaded. wp_enqueue_style( 'jquery-confirm', WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.css', null, '1.0.0' ); wp_enqueue_script( 'jquery-confirm', WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.js', [ 'jquery' ], '1.0.0', false ); // Support for the legacy form selector. // It is located in the common namespace. if ( $this->is_legacy_block() ) { wp_enqueue_script( 'wpforms-gutenberg-form-selector', WPFORMS_PLUGIN_URL . "assets/js/integrations/gutenberg/formselector-legacy.es5{$min}.js", [ 'wp-blocks', 'wp-i18n', 'wp-element', 'jquery' ], WPFORMS_VERSION, true ); return; } if ( $this->render_engine === 'modern' ) { wp_enqueue_script( 'wpforms-modern', WPFORMS_PLUGIN_URL . "assets/js/frontend/wpforms-modern{$min}.js", [ 'wpforms-gutenberg-form-selector' ], WPFORMS_VERSION, true ); } wp_enqueue_script( 'wpforms-admin-education-core', WPFORMS_PLUGIN_URL . "assets/js/admin/education/core{$min}.js", [ 'jquery', 'jquery-confirm' ], WPFORMS_VERSION, true ); wp_localize_script( 'wpforms-admin-education-core', 'wpforms_education', $this->get_js_strings() ); } /** * Whether the block is legacy. * * @since 1.8.8 */ protected function is_legacy_block() { return version_compare( $GLOBALS['wp_version'], '6.0', '<' ); } /** * Register API route for Gutenberg block. * * @since 1.8.4 * @deprecated 1.8.8 */ public function register_api_route() { _deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::register_api_routes()' ); $this->rest_api_obj->register_api_routes(); } /** * Wrap localized data in a protected WP_REST_Response object. * * @since 1.8.4 * @deprecated 1.8.8 * * @see https://developer.wordpress.org/reference/functions/rest_ensure_response/ * * @return WP_Error|WP_REST_Response */ public function protected_data_callback() { _deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::get_forms()' ); return $this->rest_api_obj->get_forms(); } /** * Check if a user has permission to access private data. * * @since 1.8.4 * @deprecated 1.8.8 * * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/routes-and-endpoints/#permissions-callback * * @return true|WP_Error True if a user has permission. */ public function protected_permissions_callback() { _deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin', '\WPForms\Integrations\Gutenberg\RestApi::permissions_check()' ); return $this->rest_api_obj->permissions_check(); } /** * Get localize data. * * @since 1.8.1 * * @return array */ public function get_localize_data(): array { $strings = [ 'title' => esc_html__( 'WPForms', 'wpforms-lite' ), 'description' => esc_html__( 'Select and display one of your forms.', 'wpforms-lite' ), 'form_keywords' => [ esc_html__( 'form', 'wpforms-lite' ), esc_html__( 'contact', 'wpforms-lite' ), esc_html__( 'survey', 'wpforms-lite' ), ], 'form_select' => esc_html__( 'Select a Form', 'wpforms-lite' ), 'form_settings' => esc_html__( 'Form Settings', 'wpforms-lite' ), 'form_edit' => esc_html__( 'Edit Form', 'wpforms-lite' ), 'form_entries' => esc_html__( 'View Entries', 'wpforms-lite' ), 'themes' => esc_html__( 'Themes', 'wpforms-lite' ), 'theme_name' => esc_html__( 'Theme Name', 'wpforms-lite' ), 'theme_delete' => esc_html__( 'Delete Theme', 'wpforms-lite' ), 'theme_delete_title' => esc_html__( 'Delete Form Theme', 'wpforms-lite' ), // Translators: %1$s: Theme name. 'theme_delete_confirm' => esc_html__( 'Are you sure you want to delete the %1$s theme?', 'wpforms-lite' ), 'theme_delete_cant_undone' => esc_html__( 'This cannot be undone.', 'wpforms-lite' ), 'theme_delete_yes' => esc_html__( 'Yes, Delete', 'wpforms-lite' ), 'theme_copy' => esc_html__( 'Copy', 'wpforms-lite' ), 'theme_custom' => esc_html__( 'Custom Theme', 'wpforms-lite' ), 'theme_noname' => esc_html__( 'Noname Theme', 'wpforms-lite' ), 'field_styles' => esc_html__( 'Field Styles', 'wpforms-lite' ), 'field_label' => esc_html__( 'Field Label', 'wpforms-lite' ), 'field_sublabel' => esc_html__( 'Field Sublabel', 'wpforms-lite' ), 'field_border' => esc_html__( 'Field Border', 'wpforms-lite' ), 'label_styles' => esc_html__( 'Label Styles', 'wpforms-lite' ), 'button_background' => esc_html__( 'Button Background', 'wpforms-lite' ), 'button_text' => esc_html__( 'Button Text', 'wpforms-lite' ), 'button_styles' => esc_html__( 'Button Styles', 'wpforms-lite' ), 'container_styles' => esc_html__( 'Container Styles', 'wpforms-lite' ), 'background_styles' => esc_html__( 'Background Styles', 'wpforms-lite' ), 'remove_image' => esc_html__( 'Remove Image', 'wpforms-lite' ), 'position' => esc_html__( 'Position', 'wpforms-lite' ), 'top_left' => esc_html__( 'Top Left', 'wpforms-lite' ), 'top_center' => esc_html__( 'Top Center', 'wpforms-lite' ), 'top_right' => esc_html__( 'Top Right', 'wpforms-lite' ), 'center_left' => esc_html__( 'Center Left', 'wpforms-lite' ), 'center_center' => esc_html__( 'Center Center', 'wpforms-lite' ), 'center_right' => esc_html__( 'Center Right', 'wpforms-lite' ), 'bottom_left' => esc_html__( 'Bottom Left', 'wpforms-lite' ), 'bottom_center' => esc_html__( 'Bottom Center', 'wpforms-lite' ), 'bottom_right' => esc_html__( 'Bottom Right', 'wpforms-lite' ), 'repeat' => esc_html__( 'Repeat', 'wpforms-lite' ), 'no_repeat' => esc_html__( 'No Repeat', 'wpforms-lite' ), 'repeat_x' => esc_html__( 'Repeat Horizontal', 'wpforms-lite' ), 'repeat_y' => esc_html__( 'Repeat Vertical', 'wpforms-lite' ), 'tile' => esc_html__( 'Tile', 'wpforms-lite' ), 'cover' => esc_html__( 'Cover', 'wpforms-lite' ), 'dimensions' => esc_html__( 'Dimensions', 'wpforms-lite' ), 'width' => esc_html__( 'Width', 'wpforms-lite' ), 'height' => esc_html__( 'Height', 'wpforms-lite' ), 'button_color_notice' => esc_html__( 'Also used for other fields like Multiple Choice, Checkboxes, Rating, and NPS Survey.', 'wpforms-lite' ), 'advanced' => esc_html__( 'Advanced', 'wpforms-lite' ), 'additional_css_classes' => esc_html__( 'Additional CSS Classes', 'wpforms-lite' ), 'form_selected' => esc_html__( 'Form', 'wpforms-lite' ), 'show_title' => esc_html__( 'Show Title', 'wpforms-lite' ), 'show_description' => esc_html__( 'Show Description', 'wpforms-lite' ), 'panel_notice_head' => esc_html__( 'Heads up!', 'wpforms-lite' ), 'panel_notice_text' => esc_html__( 'Do not forget to test your form.', 'wpforms-lite' ), 'panel_notice_link' => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/how-to-properly-test-your-wordpress-forms-before-launching-checklist/', 'gutenberg' ) ), 'panel_notice_link_text' => esc_html__( 'Check out our complete guide!', 'wpforms-lite' ), 'update_wp_notice_head' => esc_html__( 'Want to customize your form styles without editing CSS?', 'wpforms-lite' ), 'update_wp_notice_text' => esc_html__( 'Update WordPress to the latest version to use our modern markup and unlock the controls below.', 'wpforms-lite' ), 'update_wp_notice_link' => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/styling-your-forms/', 'Block Settings', 'Form Styles Documentation' ) ), 'learn_more' => esc_html__( 'Learn more', 'wpforms-lite' ), 'use_modern_notice_head' => esc_html__( 'Want to customize your form styles without editing CSS?', 'wpforms-lite' ), 'use_modern_notice_text' => esc_html__( 'Enable modern markup in your WPForms settings to unlock the controls below.', 'wpforms-lite' ), 'use_modern_notice_link' => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/styling-your-forms/', 'Block Settings', 'Form Styles Documentation' ) ), 'lead_forms_panel_notice_head' => esc_html__( 'Form Styles are disabled because Lead Form Mode is turned on.', 'wpforms-lite' ), 'lead_forms_panel_notice_text' => esc_html__( 'To change the styling for this form, open it in the form builder and edit the options in the Lead Forms settings.', 'wpforms-lite' ), 'size' => esc_html__( 'Size', 'wpforms-lite' ), 'padding' => esc_html__( 'Padding', 'wpforms-lite' ), 'background' => esc_html__( 'Background', 'wpforms-lite' ), 'border' => esc_html__( 'Border', 'wpforms-lite' ), 'text' => esc_html__( 'Text', 'wpforms-lite' ), 'menu' => esc_html__( 'Menu', 'wpforms-lite' ), 'image' => esc_html__( 'Image', 'wpforms-lite' ), 'media_library' => esc_html__( 'Media Library', 'wpforms-lite' ), 'choose_image' => esc_html__( 'Choose Image', 'wpforms-lite' ), 'stock_photo' => esc_html__( 'Stock Photo', 'wpforms-lite' ), 'border_radius' => esc_html__( 'Border Radius', 'wpforms-lite' ), 'border_size' => esc_html__( 'Border Size', 'wpforms-lite' ), 'border_style' => esc_html__( 'Border Style', 'wpforms-lite' ), 'none' => esc_html__( 'None', 'wpforms-lite' ), 'solid' => esc_html__( 'Solid', 'wpforms-lite' ), 'dashed' => esc_html__( 'Dashed', 'wpforms-lite' ), 'dotted' => esc_html__( 'Dotted', 'wpforms-lite' ), 'double' => esc_html__( 'Double', 'wpforms-lite' ), 'shadow_size' => esc_html__( 'Shadow', 'wpforms-lite' ), 'border_width' => esc_html__( 'Border Size', 'wpforms-lite' ), 'border_color' => esc_html__( 'Border', 'wpforms-lite' ), 'colors' => esc_html__( 'Colors', 'wpforms-lite' ), 'label' => esc_html__( 'Label', 'wpforms-lite' ), 'sublabel_hints' => esc_html__( 'Sublabel & Hint', 'wpforms-lite' ), 'error_message' => esc_html__( 'Error Message', 'wpforms-lite' ), 'small' => esc_html__( 'Small', 'wpforms-lite' ), 'medium' => esc_html__( 'Medium', 'wpforms-lite' ), 'large' => esc_html__( 'Large', 'wpforms-lite' ), 'btn_yes' => esc_html__( 'Yes', 'wpforms-lite' ), 'btn_no' => esc_html__( 'No', 'wpforms-lite' ), 'copy_paste_settings' => esc_html__( 'Copy / Paste Style Settings', 'wpforms-lite' ), 'copy_paste_error' => esc_html__( 'There was an error parsing your JSON code. Please check your code and try again.', 'wpforms-lite' ), 'copy_paste_notice' => esc_html__( 'If you\'ve copied style settings from another form, you can paste them here to add the same styling to this form. Any current style settings will be overwritten.', 'wpforms-lite' ), 'custom_css' => esc_html__( 'Custom CSS', 'wpforms-lite' ), 'custom_css_notice' => esc_html__( 'Further customize the look of this form without having to edit theme files.', 'wpforms-lite' ), // Translators: %1$s: Opening strong tag, %2$s: Closing strong tag. 'wpforms_empty_info' => sprintf( esc_html__( 'You can use %1$sWPForms%2$s to build contact forms, surveys, payment forms, and more with just a few clicks.', 'wpforms-lite' ), '<strong>','</strong>' ), // Translators: %1$s: Opening anchor tag, %2$s: Closing achor tag. 'wpforms_empty_help' => sprintf( esc_html__( 'Need some help? Check out our %1$scomprehensive guide.%2$s', 'wpforms-lite' ), '<a target="_blank" href="' . esc_url( wpforms_utm_link( 'https://wpforms.com/docs/creating-first-form/', 'gutenberg', 'Create Your First Form Documentation' ) ) . '">','</a>' ), 'other_styles' => esc_html__( 'Other Styles', 'wpforms-lite' ), 'page_break' => esc_html__( 'Page Break', 'wpforms-lite' ), 'rating' => esc_html__( 'Rating', 'wpforms-lite' ), 'heads_up' => esc_html__( 'Heads Up!', 'wpforms-lite' ), 'form_not_available_message' => esc_html__( 'It looks like the form you had selected is in the Trash or has been permanently deleted.', 'wpforms-lite' ), ]; return [ 'logo_url' => WPFORMS_PLUGIN_URL . 'assets/images/wpforms-logo.svg', 'block_preview_url' => WPFORMS_PLUGIN_URL . 'assets/images/integrations/gutenberg/block-preview.png', 'block_empty_url' => WPFORMS_PLUGIN_URL . 'assets/images/empty-states/no-forms.svg', 'route_namespace' => RestApi::ROUTE_NAMESPACE, 'wpnonce' => wp_create_nonce( 'wpforms-gutenberg-form-selector' ), 'urls' => [ 'form_url' => admin_url( 'admin.php?page=wpforms-builder&view=fields&form_id={ID}' ), 'entries_url' => admin_url( 'admin.php?view=list&page=wpforms-entries&form_id={ID}' ), ], 'forms' => $this->get_form_list(), 'strings' => $strings, 'isPro' => wpforms()->is_pro(), 'defaults' => self::DEFAULT_ATTRIBUTES, 'is_modern_markup' => $this->render_engine === 'modern', 'is_full_styling' => $this->disable_css_setting === 1, 'wpforms_guide' => esc_url( wpforms_utm_link( 'https://wpforms.com/docs/creating-first-form/', 'gutenberg', 'Create Your First Form Documentation' ) ), 'get_started_url' => esc_url( admin_url( 'admin.php?page=wpforms-builder' ) ), 'sizes' => [ 'field-size' => CSSVars::FIELD_SIZE, 'label-size' => CSSVars::LABEL_SIZE, 'button-size' => CSSVars::BUTTON_SIZE, 'container-shadow-size' => CSSVars::CONTAINER_SHADOW_SIZE, ], ]; } /** * Get the form list. * * @since 1.8.8 * * @return array * @noinspection NullPointerExceptionInspection */ public function get_form_list(): array { $forms = wpforms()->obj( 'form' )->get( '', [ 'order' => 'DESC' ] ); if ( empty( $forms ) ) { return []; } return array_map( static function ( $form ) { $form->post_title = htmlspecialchars_decode( $form->post_title, ENT_QUOTES ); $max_length = 47; $form->post_title = trim( mb_substr( trim( $form->post_title ), 0, $max_length ) ); $form->post_title = mb_strlen( $form->post_title ) === $max_length ? $form->post_title . '…' : $form->post_title; return $form; }, $forms ); } /** * Let's WP know that we have translation strings on our block script. * * @since 1.8.3 * @deprecated 1.8.5 */ public function enable_block_translations() { _deprecated_function( __METHOD__, '1.8.5' ); } /** * Filter form action. * * @since 1.8.8 * * @param string|mixed $action Form action. * @param array|mixed $form_data Form data. * * @return string */ public function form_action_filter( $action, $form_data ): string { if ( $this->is_gb_editor() ) { // Remove inappropriate form action URL that contains all the block attributes. $action = ''; } return (string) $action; } /** * Get form HTML to display in a WPForms Gutenberg block. * * @since 1.4.8 * * @param array|mixed $attr Attributes passed by WPForms Gutenberg block. * * @return string */ public function get_form_html( $attr ): string { $attr = (array) $attr; $id = ! empty( $attr['formId'] ) ? absint( $attr['formId'] ) : 0; $this->current_form_id = $id; if ( empty( $id ) ) { return ''; } if ( $this->is_gb_editor() ) { $this->disable_fields_in_gb_editor(); } $title = ! empty( $attr['displayTitle'] ); $desc = ! empty( $attr['displayDesc'] ); $this->add_class_callback( $id, $attr ); // Maybe override block attributes with the theme settings. $attr = $this->maybe_override_block_attributes( $attr ); // Get block content. $content = $this->get_content( $id, $title, $desc, $attr ); // phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName /** * Filter Gutenberg block content. * * @since 1.5.8.2 * * @param string $content Block content. * @param int $id Form id. */ return (string) apply_filters( 'wpforms_gutenberg_block_form_content', $content, $id ); // phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName } /** * Maybe override block attributes. * * This method is used to override block attributes with the theme settings. * * @since 1.8.8 * * @param array $attr Attributes passed by WPForms Gutenberg block. * * @return array */ private function maybe_override_block_attributes( array $attr ): array { $theme_slug = (string) ( $attr['theme'] ?? '' ); // Previously added blocks (FS 1.0) don't have the themeName attribute. // To preserve existing styling of such old blocks, we shouldn't override attributes. if ( ! isset( $attr['themeName'] ) || ( empty( $attr['themeName'] ) && $theme_slug === 'default' ) ) { return $attr; } $theme_data = $this->themes_data_obj->get_theme( $theme_slug ); // Theme doesn't exist, let's return. if ( ! $theme_data ) { return $attr; } // Override block attributes with the theme settings. return array_merge( $attr, $theme_data['settings'] ); } /** * Add class callback. * * @since 1.8.1 * * @param int $id Form id. * @param array $attr Form attributes. * * @return void */ private function add_class_callback( $id, $attr ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks $class_callback = static function ( $classes, $form_data ) use ( $id, $attr ) { if ( (int) $form_data['id'] !== $id ) { return $classes; } $cls = []; // Add custom class to form container. if ( ! empty( $attr['className'] ) ) { $cls = array_map( 'esc_attr', explode( ' ', $attr['className'] ) ); } // Add classes to identify that the form displays inside the block. $cls[] = 'wpforms-block'; if ( ! empty( $attr['clientId'] ) ) { $cls[] = 'wpforms-block-' . $attr['clientId']; } return array_unique( array_merge( $classes, $cls ) ); }; if ( empty( $this->callbacks[ $id ] ) ) { add_filter( 'wpforms_frontend_container_class', $class_callback, 10, 2 ); } $this->callbacks[ $id ][] = $class_callback; } /** * Get content. * * @since 1.8.1 * * @param int $id Form id. * @param bool $title Form title is not empty. * @param bool $desc Form desc is not empty. * @param array $attr Form attributes. * * @return string */ private function get_content( $id, $title, $desc, $attr ): string { /** * Filter allow render block content flag. * * @since 1.8.8 * * @param bool $allow_render Allow render flag. Defaults to `true`. */ $allow_render = (bool) apply_filters( 'wpforms_integrations_gutenberg_form_selector_allow_render', true ); if ( ! $allow_render ) { return ''; } ob_start(); // phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName /** * Fires before Gutenberg block output. * * @since 1.5.8.2 */ do_action( 'wpforms_gutenberg_block_before' ); /** * Filter block title display flag. * * @since 1.5.8.2 * * @param bool $title Title display flag. * @param int $id Form id. */ $title = (bool) apply_filters( 'wpforms_gutenberg_block_form_title', $title, $id ); /** * Filter block description display flag. * * @since 1.5.8.2 * * @param bool $desc Description display flag. * @param int $id Form id. */ $desc = (bool) apply_filters( 'wpforms_gutenberg_block_form_desc', $desc, $id ); $this->output_css_vars( $attr ); $this->output_custom_css( $attr ); wpforms_display( $id, $title, $desc ); /** * Fires after Gutenberg block output. * * @since 1.5.8.2 */ do_action( 'wpforms_gutenberg_block_after' ); // phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName $content = (string) ob_get_clean(); if ( ! $this->is_gb_editor() ) { return $content; } if ( empty( $content ) ) { return '<div class="components-placeholder"><div class="components-placeholder__label"></div>' . '<div class="components-placeholder__fieldset">' . esc_html__( 'The form cannot be displayed.', 'wpforms-lite' ) . '</div></div>'; } /** * Unfortunately, the inline 'script' tag cannot be executed in the GB editor. * This is the hacky way to trigger custom event on form loaded in the Block Editor / GB / FSE. */ // phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export $content .= sprintf( '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" onLoad=" window.top.dispatchEvent( new CustomEvent( \'wpformsFormSelectorFormLoaded\', { detail: { formId: %1$s, title: %2$s, desc: %3$s, block: this.closest( \'.wp-block\' ) } } ) ); " class="wpforms-pix-trigger" alt="">', absint( $id ), var_export( (bool) $title, true ), var_export( (bool) $desc, true ) ); // phpcs:enable WordPress.PHP.DevelopmentFunctions.error_log_var_export return $content; } /** * Checking if is Gutenberg REST API call. * * @since 1.5.7 * * @return bool True if is Gutenberg REST API call. */ public function is_gb_editor(): bool { // TODO: Find a better way to check if is GB editor API call. // phpcs:ignore WordPress.Security.NonceVerification.Recommended return defined( 'REST_REQUEST' ) && REST_REQUEST && ! empty( $_REQUEST['context'] ) && $_REQUEST['context'] === 'edit'; } /** * Disable form fields if called from the Gutenberg editor. * * @since 1.7.5 * * @return void */ private function disable_fields_in_gb_editor() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks add_filter( 'wpforms_frontend_container_class', static function ( $classes ) { $classes[] = 'wpforms-gutenberg-form-selector'; return $classes; } ); add_action( 'wpforms_frontend_output', static function () { echo '<fieldset disabled>'; }, 3 ); add_action( 'wpforms_frontend_output', static function () { echo '</fieldset>'; }, 30 ); } /** * Output CSS variables for the particular form. * * @since 1.8.1 * * @param array $attr Attributes passed by WPForms Gutenberg block. */ private function output_css_vars( $attr ) { if ( empty( $this->css_vars_obj ) || ! method_exists( $this->css_vars_obj, 'get_vars' ) ) { return; } $this->css_vars_obj->output_root(); if ( $this->render_engine === 'classic' || $this->disable_css_setting !== 1 ) { return; } $css_vars = $this->css_vars_obj->get_customized_css_vars( $attr ); if ( empty( $css_vars ) ) { return; } $style_id = "#wpforms-css-vars-{$attr['formId']}-block-{$attr['clientId']}"; /** * Filter the CSS selector for output CSS variables for styling the GB block form. * * @since 1.8.1 * * @param string $selector The CSS selector for output CSS variables for styling the GB block form. * @param array $attr Attributes passed by WPForms Gutenberg block. * @param array $css_vars CSS variables data. */ $vars_selector = apply_filters( 'wpforms_integrations_gutenberg_form_selector_output_css_vars_selector', "#wpforms-{$attr['formId']}.wpforms-block-{$attr['clientId']}", $attr, $css_vars ); $this->css_vars_obj->output_selector_vars( $vars_selector, $css_vars, $style_id, $this->current_form_id ); } /** * Output custom CSS styles. * * @since 1.8.8 * * @param array $attr Attributes passed by WPForms Gutenberg block. */ private function output_custom_css( $attr ) { if ( wpforms_get_render_engine() === 'classic' ) { return; } $custom_css = trim( $attr['customCss'] ?? '' ); if ( empty( $custom_css ) ) { return; } $style_id = "#wpforms-custom-css-{$attr['formId']}-block-{$attr['clientId']}"; printf( '<style id="%1$s"> %2$s </style>', sanitize_key( $style_id ), esc_html( $custom_css ) ); } /** * Disable loading media for the richtext editor for edit action to prevent script conflicts. * * @since 1.9.1 * * @param bool|mixed $media_enabled Whether to enable media. * @param array $field Field data. * * @return bool */ public function disable_richtext_media( $media_enabled, array $field ): bool { // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] === 'edit' && is_admin() ) { return false; } return (bool) $media_enabled; } }