Current File : /var/www/pediatribu/wp-content/plugins/wpforms-lite/includes/admin/builder/class-builder.php
<?php

// phpcs:disable Generic.Commenting.DocComment.MissingShort
/** @noinspection PhpIllegalPsrClassPathInspection */
/** @noinspection AutoloadingIssuesInspection */
// phpcs:enable Generic.Commenting.DocComment.MissingShort

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use WPForms\Integrations\AI\Helpers as AIHelpers;

/**
 * Form builder that contains magic.
 *
 * @since 1.0.0
 * @since 1.6.8 Form Builder Refresh.
 *                  - Added `deregister_common_wp_admin_styles()` method.
 *                  - Changed logic of enqueue styles.
 */
class WPForms_Builder {

	/**
	 * Abort. Bail on proceeding to process the page.
	 *
	 * @since 1.7.3
	 *
	 * @var bool
	 */
	public $abort = false;

	/**
	 * The human-readable error message.
	 *
	 * @since 1.7.3
	 *
	 * @var string
	 */
	private $abort_message;

	/**
	 * One is the loneliest number that you'll ever do.
	 *
	 * @since 1.4.4.1
	 *
	 * @var object
	 */
	private static $instance;

	/**
	 * Current view (panel).
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	public $view;

	/**
	 * Available panels.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	public $panels;

	/**
	 * Current form.
	 *
	 * @since 1.0.0
	 *
	 * @var WP_Post
	 */
	public $form;

	/**
	 * Form data and settings.
	 *
	 * @since 1.4.4.1
	 *
	 * @var array
	 */
	public $form_data;

	/**
	 * Current template information.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	public $template;

	/**
	 * Main Instance.
	 *
	 * @since 1.4.4.1
	 *
	 * @return WPForms_Builder
	 */
	public static function instance() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		if ( ! isset( self::$instance ) && ! ( self::$instance instanceof self ) ) {

			self::$instance = new self();

			add_action( 'admin_init', [ self::$instance, 'init' ] );
			add_action( 'admin_init', [ self::$instance, 'deregister_common_wp_admin_styles' ], PHP_INT_MAX );
			add_action( 'load-wpforms_page_wpforms-builder', [ self::$instance, 'process_actions' ] );
		}

		return self::$instance;
	}

	/**
	 * Determine if the user is viewing the builder, if so, party on.
	 *
	 * @since 1.0.0
	 */
	public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks, Generic.Metrics.CyclomaticComplexity.MaxExceeded

		// Only load if we are actually on the builder.
		if ( ! wpforms_is_admin_page( 'builder' ) ) {
			return;
		}

		// Load form if found.
		$form_id = isset( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		// Abort early if form ID is set, but the value is empty, 0 or any non-numeric value.
		if ( $form_id === 0 ) {
			wp_die( esc_html__( 'It looks like the form you are trying to access is no longer available.', 'wpforms-lite' ), 403 );
		}

		if ( $form_id ) {
			// Default view for with an existing form is fields panel.
			$this->view = isset( $_GET['view'] ) ? sanitize_key( $_GET['view'] ) : 'fields'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		} else {
			// The default view for new form is the setup panel.
			$this->view = isset( $_GET['view'] ) ? sanitize_key( $_GET['view'] ) : 'setup'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		}

		if ( $this->view === 'setup' && ! wpforms_current_user_can( 'create_forms' ) ) {
			wp_die( esc_html__( 'Sorry, you are not allowed to create new forms.', 'wpforms-lite' ), 403 );
		}

		if ( $this->view === 'fields' && ! wpforms_current_user_can( 'edit_form_single', $form_id ) ) {
			wp_die( esc_html__( 'Sorry, you are not allowed to edit this form.', 'wpforms-lite' ), 403 );
		}

		// Fetch form.
		$this->form = wpforms()->obj( 'form' )->get( $form_id );

		if ( ! empty( $form_id ) && empty( $this->form ) ) {
			$this->abort_message = esc_html__( 'It looks like the form you are trying to access is no longer available.', 'wpforms-lite' );
			$this->abort         = true;
		}

		if ( ! empty( $this->form->post_status ) && $this->form->post_status === 'trash' ) {
			$this->abort_message = esc_html__( 'You can\'t edit this form because it\'s in the trash.', 'wpforms-lite' );
			$this->abort         = true;
		}

		// Retrieve form data.
		$this->form_data = $this->form ? wpforms_decode( $this->form->post_content ) : false;

		/**
		 * Active form template data filter.
		 *
		 * Allows developers to modify fields' structure and form settings in the template of the current form.
		 *
		 * @since 1.6.8
		 *
		 * @param array $template Template data.
		 * @param array $form_id  Form ID.
		 */
		$this->template = apply_filters( 'wpforms_builder_template_active', [], $this->form );

		// Load builder panels.
		$this->load_panels();

		// Modify meta viewport tag if desktop view is forced.
		add_filter( 'admin_viewport_meta', [ $this, 'viewport_meta' ] );

		add_action( 'admin_head', [ $this, 'admin_head' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ], PHP_INT_MAX );
		add_action( 'admin_print_footer_scripts', [ $this, 'footer_scripts' ] );
		add_action( 'wpforms_admin_page', [ $this, 'output' ] );

		// Display Abort Message screen.
		add_action( 'wpforms_admin_page', [ $this, 'display_abort_message' ] );

		// Save the timestamp when the Builder has been opened for the first time.
		add_option( 'wpforms_builder_opened_date', time(), '', 'no' );

		/**
		 * Form Builder init action.
		 *
		 * Executes after all the form builder UI output.
		 * Intended to use in addons.
		 *
		 * @since 1.6.8
		 *
		 * @param string $view Current view.
		 */
		do_action( 'wpforms_builder_init', $this->view );

		add_filter( 'teeny_mce_plugins', [ $this, 'tinymce_buttons' ] );
	}

	/**
	 * Clear common wp-admin styles, keep only allowed.
	 *
	 * @since 1.6.8
	 */
	public function deregister_common_wp_admin_styles() {

		if ( ! wpforms_is_admin_page( 'builder' ) ) {
			return;
		}

		/**
		 * Filter the allowed common wp-admin styles.
		 *
		 * @since 1.6.8
		 *
		 * @param array $allowed_styles Styles allowed in the Form Builder.
		 */
		$allowed_styles = (array) apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			'wpforms_admin_builder_allowed_common_wp_admin_styles',
			[
				'wp-editor',
				'wp-editor-font',
				'editor-buttons',
				'dashicons',
				'media-views',
				'imgareaselect',
				'wp-mediaelement',
				'mediaelement',
				'buttons',
				'admin-bar',
			]
		);

		wp_styles()->registered = array_intersect_key( wp_styles()->registered, array_flip( $allowed_styles ) );
	}

	/**
	 * Process form actions.
	 *
	 * @since 1.8.8
	 */
	public function process_actions() {

		$form_id = isset( $_GET['form_id'] ) ? (int) $_GET['form_id'] : 0;
		$action  = isset( $_REQUEST['action'] ) ? sanitize_key( $_REQUEST['action'] ) : false;
		$nonce   = isset( $_GET['_wpnonce'] ) ? sanitize_key( $_GET['_wpnonce'] ) : false;

		if ( ! $this->is_allowed_action( $form_id, $action ) ) {
			return;
		}

		if ( ! wp_verify_nonce( $nonce, 'wpforms_' . $action . '_form_nonce' ) ) {
			return;
		}

		$this->process_action( $form_id, $action );
	}

	/**
	 * Check whether the form action is valid and allowed.
	 *
	 * @since 1.8.8
	 *
	 * @param int    $form_id Form ID.
	 * @param string $action  Action name.
	 *
	 * @return bool
	 */
	private function is_allowed_action( int $form_id, string $action ): bool {

		if ( empty( $form_id ) || empty( $action ) ) {
			return false;
		}

		return in_array( $action, [ 'save_as_template', 'template_to_form', 'duplicate' ], true );
	}

	/**
	 * Process a single form action.
	 *
	 * The action can be triggered via URL:
	 *   wp_nonce_url(
	 *       add_query_arg( [ 'action' => '<action>', 'form_id' => $form_id ] ),
	 *      'wpforms_save_as_template_form_nonce'
	 *   );
	 *
	 * @since 1.8.8
	 *
	 * @param int    $form_id Form ID.
	 * @param string $action  Action name.
	 */
	private function process_action( int $form_id, string $action ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$form_handler = wpforms()->obj( 'form' );

		if ( ! $form_handler ) {
			return;
		}

		$id = false;

		if ( $action === 'save_as_template' ) {
			$id = $form_handler->convert( $form_id, 'template' );
		}

		if ( $action === 'template_to_form' ) {
			$id = $form_handler->convert( $form_id, 'form' );
		}

		if ( $action === 'duplicate' ) {
			$ids = $form_handler->duplicate( $form_id );
			$id  = ! empty( $ids ) ? current( $ids ) : false;
		}

		// Reload the form builder with the target object.
		if ( ! empty( $id ) ) {
			wp_safe_redirect( $this->get_edit_url( $id, $this->view ) );
			exit;
		}
	}

	/**
	 * Get the form edit URL.
	 *
	 * @since 1.8.8
	 *
	 * @param string|int $form_id Form ID.
	 * @param string     $view    View name.
	 *
	 * @return string
	 */
	private function get_edit_url( $form_id, string $view = '' ): string {

		if ( empty( $view ) || ! in_array( $view, $this->panels, true ) ) {
			$view = 'fields';
		}

		return add_query_arg(
			[
				'view'    => $view,
				'form_id' => $form_id,
			],
			admin_url( 'admin.php?page=wpforms-builder' )
		);
	}

	/**
	 * Define TinyMCE buttons to use with our fancy editor instances.
	 *
	 * @since 1.0.3
	 *
	 * @param array $buttons List of default buttons.
	 *
	 * @return array
	 * @noinspection PhpMissingParamTypeInspection
	 * @noinspection PhpUnusedParameterInspection
	 */
	public function tinymce_buttons( $buttons ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found

		return [ 'colorpicker', 'lists', 'wordpress', 'wpeditimage', 'wplink' ];
	}

	/**
	 * Load panels.
	 *
	 * @since 1.0.0
	 */
	public function load_panels() {

		// Base class and functions.
		require_once WPFORMS_PLUGIN_DIR . 'includes/admin/builder/panels/class-base.php';

		/**
		 * Form Builder panels slugs array filter.
		 *
		 * Allows developers to disable loading of some builder panels.
		 *
		 * @since 1.0.0
		 *
		 * @param array $panels Panels slugs array.
		 */
		$this->panels = apply_filters(
			'wpforms_builder_panels',
			[
				'setup',
				'fields',
				'settings',
				'providers',
				'payments',
				'revisions',
			]
		);

		foreach ( $this->panels as $panel ) {
			$panel    = sanitize_file_name( $panel );
			$file     = WPFORMS_PLUGIN_DIR . "includes/admin/builder/panels/class-{$panel}.php";
			$file_pro = WPFORMS_PLUGIN_DIR . "pro/includes/admin/builder/panels/class-{$panel}.php";

			if ( file_exists( $file ) ) {
				require_once $file;
			} elseif ( file_exists( $file_pro ) ) {
				require_once $file_pro;
			}
		}
	}

	/**
	 * Admin head area inside the form builder.
	 *
	 * @since 1.4.6
	 */
	public function admin_head() {

		// Force hide an admin side menu.
		echo '<style>#adminmenumain { display: none !important }</style>';

		/**
		 * Form Builder admin head action.
		 *
		 * @param string $view Current view.
		 *
		 * @since 1.4.6
		 */
		do_action( 'wpforms_builder_admin_head', $this->view );
	}

	/**
	 * Enqueue assets for the builder.
	 *
	 * @since 1.0.0
	 * @since 1.6.8 All the panel's stylesheets restructured and moved here.
	 */
	public function enqueues() {

		$this->suppress_conflicts();

		/**
		 * Form Builder enqueues before action.
		 *
		 * @param string $view Current view.
		 *
		 * @since 1.0.0
		 */
		do_action( 'wpforms_builder_enqueues_before', $this->view );

		$min = wpforms_get_min_suffix();

		/*
		 * Builder CSS.
		 */
		$builder_styles = [
			'overlay',
			'basic',
			'third-party',
			'alerts',
			'ui-general',
			'panels',
			'subsystems',
			'fields',
			'fields-types',
		];

		foreach ( $builder_styles as $style ) {
			wp_enqueue_style(
				$style === 'basic' ? 'wpforms-builder' : 'wpforms-builder-' . $style,
				WPFORMS_PLUGIN_URL . "assets/css/builder/builder-{$style}{$min}.css",
				[],
				WPFORMS_VERSION
			);
		}

		/*
		 * Third-party CSS.
		 */
		wp_enqueue_style(
			'wpforms-font-awesome',
			WPFORMS_PLUGIN_URL . 'assets/lib/font-awesome/font-awesome.min.css',
			null,
			'4.7.0'
		);

		wp_enqueue_style(
			'tooltipster',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.css',
			null,
			'4.2.6'
		);

		// 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_style(
			'minicolors',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.minicolors/jquery.minicolors.min.css',
			null,
			'2.3.6'
		);

		// Remove TinyMCE editor styles from third-party themes and plugins.
		remove_editor_styles();

		/*
		 * JavaScript.
		 */
		wp_enqueue_media();
		wp_enqueue_script( 'jquery-ui-sortable' );
		wp_enqueue_script( 'jquery-ui-draggable' );
		wp_enqueue_script( 'wp-util' );

		wp_enqueue_script(
			'tooltipster',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.tooltipster/jquery.tooltipster.min.js',
			[ 'jquery' ],
			'4.2.6',
			false
		);

		// jQuery.Confirm Reloaded.
		wp_enqueue_script(
			'jquery-confirm',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.js',
			[ 'jquery' ],
			'1.0.0',
			false
		);

		wp_enqueue_script(
			'insert-at-caret',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.insert-at-caret.min.js',
			[ 'jquery' ],
			'1.1.4',
			false
		);

		wp_enqueue_script(
			'minicolors',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.minicolors/jquery.minicolors.min.js',
			[ 'jquery' ],
			'2.3.6',
			false
		);

		wp_enqueue_script(
			'conditionals',
			WPFORMS_PLUGIN_URL . 'assets/lib/jquery.conditionals.min.js',
			[ 'jquery' ],
			'1.0.1',
			false
		);

		wp_enqueue_script(
			'choicesjs',
			WPFORMS_PLUGIN_URL . 'assets/lib/choices.min.js',
			[],
			'10.2.0',
			false
		);

		wp_enqueue_script(
			'listjs',
			WPFORMS_PLUGIN_URL . 'assets/lib/list.min.js',
			[ 'jquery' ],
			'2.3.0',
			false
		);

		wp_enqueue_script(
			'dom-purify',
			WPFORMS_PLUGIN_URL . 'assets/lib/purify.min.js',
			[],
			'3.2.5',
			false
		);

		if ( wp_is_mobile() ) {
			wp_enqueue_script( 'jquery-touch-punch' );
		}

		wp_enqueue_script(
			'wpforms-utils',
			WPFORMS_PLUGIN_URL . "assets/js/admin/share/admin-utils{$min}.js",
			[ 'jquery', 'dom-purify' ],
			WPFORMS_VERSION,
			false
		);

		wp_enqueue_script(
			'wpforms-generic-utils',
			WPFORMS_PLUGIN_URL . "assets/js/share/utils{$min}.js",
			[ 'jquery' ],
			WPFORMS_VERSION,
			false
		);

		wp_enqueue_script(
			'wpforms-builder-choicesjs',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/wpforms-choicesjs{$min}.js",
			[ 'jquery', 'choicesjs' ],
			WPFORMS_VERSION,
			false
		);

		wp_enqueue_script(
			'wpforms-admin-builder-dropdown-list',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/dropdown-list{$min}.js",
			[ 'jquery', 'listjs' ],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-builder',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/admin-builder{$min}.js",
			[
				'wpforms-utils',
				'wpforms-admin-builder-templates',
				'jquery-ui-sortable',
				'jquery-ui-draggable',
				'tooltipster',
				'jquery-confirm',
				'choicesjs',
				'wpforms-builder-choicesjs',
			],
			WPFORMS_VERSION,
			false
		);

		wp_enqueue_script(
			'wpforms-admin-builder-templates',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/templates{$min}.js",
			[ 'wp-util' ],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-builder-smart-tags',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/smart-tags{$min}.js",
			[ 'wpforms-builder' ],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-builder-field-map',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/field-map{$min}.js",
			[ 'wpforms-builder' ],
			WPFORMS_VERSION,
			true
		);

		wp_localize_script(
			'wpforms-builder',
			'wpforms_builder',
			$this->get_localized_strings()
		);

		/**
		 * Form Builder enqueues action.
		 *
		 * Executes after all the form builder assets were enqueued.
		 * Intended to use in addons.
		 *
		 * @since 1.0.0
		 *
		 * @param string $view Current view.
		 */
		do_action( 'wpforms_builder_enqueues', $this->view );
	}

	/**
	 * Remove conflicting scripts and styles.
	 *
	 * @since 1.9.0
	 */
	private function suppress_conflicts() {

		// Remove conflicting styles (e.g., WP JobSearch plugin).
		wp_deregister_style( 'font-awesome' );

		// Remove conflicting scripts.
		wp_deregister_script( 'serialize-object' );
		wp_deregister_script( 'wpclef-ajax-settings' );
	}

	/**
	 * Get localized strings.
	 *
	 * @since 1.6.8
	 *
	 * @return array
	 * @noinspection HtmlUnknownTarget
	 */
	private function get_localized_strings(): array { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$image_extensions = wpforms_chain( get_allowed_mime_types() )
			->map(
				static function ( $mime ) {

					return strpos( $mime, 'image/' ) === 0 ? $mime : '';
				}
			)
			->array_filter()
			->array_values()
			->value();

		$strings = [
			'and'                                     => esc_html__( 'And', 'wpforms-lite' ),
			'ajax_url'                                => admin_url( 'admin-ajax.php' ),
			'bulk_add_button'                         => esc_html__( 'Add New Choices', 'wpforms-lite' ),
			'bulk_add_show'                           => esc_html__( 'Bulk Add', 'wpforms-lite' ),
			'are_you_sure_to_close'                   => esc_html__( 'Are you sure you want to leave? You have unsaved changes', 'wpforms-lite' ),
			'bulk_add_hide'                           => esc_html__( 'Hide Bulk Add', 'wpforms-lite' ),
			'bulk_add_heading'                        => esc_html__( 'Add Choices (one per line)', 'wpforms-lite' ),
			'bulk_add_placeholder'                    => esc_html__( "Blue\nRed\nGreen", 'wpforms-lite' ),
			'bulk_add_presets_show'                   => esc_html__( 'Show presets', 'wpforms-lite' ),
			'bulk_add_presets_hide'                   => esc_html__( 'Hide presets', 'wpforms-lite' ),
			'date_select_day'                         => 'DD',
			'date_select_month'                       => 'MM',
			'debug'                                   => wpforms_debug(),
			'dynamic_choices'                         => [
				'limit_message' => sprintf( /* translators: %1$s - data source name (e.g. Categories, Posts), %2$s - data source type (e.g. post type, taxonomy), %3$s - display limit, %4$s - total number of items. */
					esc_html__( 'The %1$s %2$s contains over %3$s items (%4$s). This may make the field difficult for your visitors to use and/or cause the form to be slow.', 'wpforms-lite' ),
					'{source}',
					'{type}',
					'{limit}',
					'{total}'
				),
				'empty_message' => sprintf( /* translators: %1$s - data source name (e.g. Categories, Posts), %2$s - data source type (e.g. post type, taxonomy). */
					esc_html__( 'This field will not be displayed in your form since there are no %2$s belonging to %1$s.', 'wpforms-lite' ),
					'{source}',
					'{type}'
				),
				'entities'      => [
					'post_type' => esc_html__( 'posts', 'wpforms-lite' ),
					'taxonomy'  => esc_html__( 'terms', 'wpforms-lite' ),
				],
			],
			'cancel'                                  => esc_html__( 'Cancel', 'wpforms-lite' ),
			'ok'                                      => esc_html__( 'OK', 'wpforms-lite' ),
			'close'                                   => esc_html__( 'Close', 'wpforms-lite' ),
			'conditionals_change'                     => esc_html__( 'Due to form changes, conditional logic rules will be removed or updated:', 'wpforms-lite' ),
			'conditionals_disable'                    => esc_html__( 'Are you sure you want to disable conditional logic? This will remove the rules for this field or setting.', 'wpforms-lite' ),
			'field'                                   => esc_html__( 'Field', 'wpforms-lite' ),
			'field_locked'                            => esc_html__( 'Field Locked', 'wpforms-lite' ),
			'field_locked_msg'                        => esc_html__( 'This field cannot be deleted or duplicated.', 'wpforms-lite' ),
			'field_locked_no_delete_msg'              => esc_html__( 'This field cannot be deleted.', 'wpforms-lite' ),
			'field_locked_no_duplicate_msg'           => esc_html__( 'This field cannot be duplicated.', 'wpforms-lite' ),
			'fields_available'                        => esc_html__( 'Available Fields', 'wpforms-lite' ),
			'fields_unavailable'                      => esc_html__( 'No fields available', 'wpforms-lite' ),
			'heads_up'                                => esc_html__( 'Heads up!', 'wpforms-lite' ),
			'image_placeholder'                       => WPFORMS_PLUGIN_URL . 'assets/images/builder/placeholder-200x125.svg',
			'nonce'                                   => wp_create_nonce( 'wpforms-builder' ),
			'admin_nonce'                             => wp_create_nonce( 'wpforms-admin' ),
			'no_email_fields'                         => esc_html__( 'No email fields', 'wpforms-lite' ),
			'notification_delete'                     => esc_html__( 'Are you sure you want to delete this notification?', 'wpforms-lite' ),
			'notification_prompt'                     => esc_html__( 'Enter a notification name', 'wpforms-lite' ),
			'notification_ph'                         => esc_html__( 'Eg: User Confirmation', 'wpforms-lite' ),
			'notification_error'                      => esc_html__( 'You must provide a notification name', 'wpforms-lite' ),
			'notification_def_name'                   => esc_html__( 'Default Notification', 'wpforms-lite' ),
			'confirmation_delete'                     => esc_html__( 'Are you sure you want to delete this confirmation?', 'wpforms-lite' ),
			'confirmation_prompt'                     => esc_html__( 'Enter a confirmation name', 'wpforms-lite' ),
			'confirmation_ph'                         => esc_html__( 'Eg: Alternative Confirmation', 'wpforms-lite' ),
			'confirmation_error'                      => esc_html__( 'You must provide a confirmation name', 'wpforms-lite' ),
			'confirmation_def_name'                   => esc_html__( 'Default Confirmation', 'wpforms-lite' ),
			'save'                                    => esc_html__( 'Save', 'wpforms-lite' ),
			'saving'                                  => esc_html__( 'Saving', 'wpforms-lite' ),
			'saved'                                   => esc_html__( 'Saved!', 'wpforms-lite' ),
			'save_exit'                               => esc_html__( 'Save and Exit', 'wpforms-lite' ),
			'save_embed'                              => esc_html__( 'Save and Embed', 'wpforms-lite' ),
			'saved_state'                             => '',
			'layout_selector_show'                    => esc_html__( 'Show Layouts', 'wpforms-lite' ),
			'layout_selector_hide'                    => esc_html__( 'Hide Layouts', 'wpforms-lite' ),
			'layout_selector_layout'                  => esc_html__( 'Select your layout', 'wpforms-lite' ),
			'layout_selector_column'                  => esc_html__( 'Select your column', 'wpforms-lite' ),
			'loading'                                 => esc_html__( 'Loading', 'wpforms-lite' ),
			'template_name'                           => ! empty( $this->template['name'] ) ? $this->template['name'] : '',
			'template_slug'                           => ! empty( $this->template['slug'] ) ? $this->template['slug'] : '',
			'template_modal_title'                    => ! empty( $this->template['modal']['title'] ) ? $this->template['modal']['title'] : '',
			'template_modal_msg'                      => ! empty( $this->template['modal']['message'] ) ? $this->template['modal']['message'] : '',
			'template_modal_display'                  => ! empty( $this->template['modal_display'] ) ? $this->template['modal_display'] : '',
			'template_select'                         => esc_html__( 'Use Template', 'wpforms-lite' ),
			'template_confirm'                        => esc_html__( 'Changing the template on this form will delete existing fields, reset external connections, and unsaved changes will be lost. Are you sure you want to apply the new template?', 'wpforms-lite' ),
			'use_default_template'                    => esc_html__( 'Use Default Template', 'wpforms-lite' ),
			'embed'                                   => esc_html__( 'Embed', 'wpforms-lite' ),
			'exit'                                    => esc_html__( 'Exit', 'wpforms-lite' ),
			'exit_url'                                => wpforms_current_user_can( 'view_forms' ) ? admin_url( 'admin.php?page=wpforms-overview' ) : admin_url(),
			'exit_confirm'                            => esc_html__( 'Your form contains unsaved changes. Would you like to save your changes first.', 'wpforms-lite' ),
			'delete_confirm'                          => esc_html__( 'Are you sure you want to delete this field?', 'wpforms-lite' ),
			'delete_choice_confirm'                   => esc_html__( 'Are you sure you want to delete this choice?', 'wpforms-lite' ),
			'duplicate_confirm'                       => esc_html__( 'Are you sure you want to duplicate this field?', 'wpforms-lite' ),
			'duplicate_copy'                          => esc_html__( '(copy)', 'wpforms-lite' ),
			'error_title'                             => esc_html__( 'Please enter a form name.', 'wpforms-lite' ),
			'error_choice'                            => esc_html__( 'This item must contain at least one choice.', 'wpforms-lite' ),
			'off'                                     => esc_html__( 'Off', 'wpforms-lite' ),
			'on'                                      => esc_html__( 'On', 'wpforms-lite' ),
			'or'                                      => esc_html__( 'or', 'wpforms-lite' ),
			'other'                                   => esc_html__( 'Other', 'wpforms-lite' ),
			'operator_is'                             => esc_html__( 'is', 'wpforms-lite' ),
			'operator_is_not'                         => esc_html__( 'is not', 'wpforms-lite' ),
			'operator_empty'                          => esc_html__( 'empty', 'wpforms-lite' ),
			'operator_not_empty'                      => esc_html__( 'not empty', 'wpforms-lite' ),
			'operator_contains'                       => esc_html__( 'contains', 'wpforms-lite' ),
			'operator_not_contains'                   => esc_html__( 'does not contain', 'wpforms-lite' ),
			'operator_starts'                         => esc_html__( 'starts with', 'wpforms-lite' ),
			'operator_ends'                           => esc_html__( 'ends with', 'wpforms-lite' ),
			'operator_greater_than'                   => esc_html__( 'greater than', 'wpforms-lite' ),
			'operator_less_than'                      => esc_html__( 'less than', 'wpforms-lite' ),
			'payments_entries_off'                    => esc_html__( 'Entry storage is currently disabled, but is required to accept payments. Please enable in your form settings.', 'wpforms-lite' ),
			'payments_on_entries_off'                 => esc_html__( 'This form is currently accepting payments. Entry storage is required to accept payments. To disable entry storage, please first disable payments.', 'wpforms-lite' ),
			'previous'                                => esc_html__( 'Previous', 'wpforms-lite' ),
			'provider_required_flds'                  => sprintf( /* translators: %s - marketing integration name. */
				esc_html__( 'In order to complete your form\'s %s integration, please check that all required (*) fields have been filled out.', 'wpforms-lite' ),
				'{provider}'
			),
			'rule_create'                             => esc_html__( 'Create new rule', 'wpforms-lite' ),
			'rule_create_group'                       => esc_html__( 'Add New Group', 'wpforms-lite' ),
			'rule_delete'                             => esc_html__( 'Delete rule', 'wpforms-lite' ),
			'smart_tags_dropdown_title'               => esc_html__( 'Smart Tags', 'wpforms-lite' ),
			'select_field'                            => esc_html__( '--- Select Field ---', 'wpforms-lite' ),
			'select_choice'                           => esc_html__( '--- Select Choice ---', 'wpforms-lite' ),
			'upload_image_title'                      => esc_html__( 'Upload or Choose Your Image', 'wpforms-lite' ),
			'upload_image_button'                     => esc_html__( 'Use Image', 'wpforms-lite' ),
			'upload_image_remove'                     => esc_html__( 'Remove Image', 'wpforms-lite' ),
			'upload_image_extensions'                 => $image_extensions,
			'upload_image_extensions_error'           => esc_html__( 'You tried uploading a file type that is not allowed. Please try again.', 'wpforms-lite' ),
			'provider_add_new_acc_btn'                => esc_html__( 'Add', 'wpforms-lite' ),
			'pro'                                     => wpforms()->is_pro(),
			'is_gutenberg'                            => ! is_plugin_active( 'classic-editor/classic-editor.php' ),
			'cl_fields_supported'                     => wpforms_get_conditional_logic_form_fields_supported(),
			'redirect_url_field_error'                => esc_html__( 'You should enter a valid absolute address to the Confirmation Redirect URL field.', 'wpforms-lite' ),
			'add_custom_value_label'                  => esc_html__( 'Add Custom Value', 'wpforms-lite' ),
			'choice_empty_label_tpl'                  => sprintf( /* translators: %s - choice number. */
				esc_html__( 'Choice %s', 'wpforms-lite' ),
				'{number}'
			),
			'payment_choice_empty_label_tpl'          => sprintf( /* translators: %s - choice number. */
				esc_html__( 'Item %s', 'wpforms-lite' ),
				'{number}'
			),
			'error_save_form'                         => esc_html__( 'Something went wrong while saving the form. Please reload the page and try again.', 'wpforms-lite' ),
			'error_contact_support'                   => esc_html__( 'Please contact the plugin support team if this behavior persists.', 'wpforms-lite' ),
			'error_select_template'                   => esc_html__( 'Something went wrong while applying the form template. Please try again. If the error persists, contact our support team.', 'wpforms-lite' ),
			'error_load_templates'                    => esc_html__( "Couldn't load the Setup panel.", 'wpforms-lite' ),
			'blank_form'                              => esc_html__( 'Blank Form', 'wpforms-lite' ),
			'something_went_wrong'                    => esc_html__( 'Something went wrong', 'wpforms-lite' ),
			'field_cannot_be_reordered'               => esc_html__( 'This field cannot be moved.', 'wpforms-lite' ),
			'empty_label'                             => esc_html__( 'Empty Label', 'wpforms-lite' ),
			'submit_text'                             => esc_html__( 'Submit', 'wpforms-lite' ),
			'name_field_formats'                      => [
				'full'   => esc_html__( 'Full', 'wpforms-lite' ),
				'first'  => esc_html__( 'First', 'wpforms-lite' ),
				'middle' => esc_html__( 'Middle', 'wpforms-lite' ),
				'last'   => esc_html__( 'Last', 'wpforms-lite' ),
			],
			'no_pages_found'                          => esc_html__( 'No results found', 'wpforms-lite' ),
			'no_results_found'                        => esc_html__( 'Sorry, no results found', 'wpforms-lite' ),
			'search'                                  => esc_html__( 'Search', 'wpforms-lite' ),
			'number_slider_error_valid_default_value' => sprintf( /* translators: %1$s - from value %2$s - to value. */
				esc_html__( 'Please enter a valid value or change the Increment. The nearest valid values are %1$s and %2$s.', 'wpforms-lite' ),
				'{from}',
				'{to}'
			),
			'form_meta'                               => $this->form_data['meta'] ?? [],
			'scrollbars_css_url'                      => WPFORMS_PLUGIN_URL . 'assets/css/builder/builder-scrollbars.css',
			'is_ai_disabled'                          => AIHelpers::is_disabled(),
			'connection_label'                        => esc_html__( 'Connection', 'wpforms-lite' ),
		];

		$strings = $this->add_localized_currencies( $strings );

		$strings['disable_entries'] = sprintf(
			wp_kses( /* translators: %s - link to the WPForms.com doc article. */
				__( 'Disabling entry storage for this form will completely prevent any new submissions from getting saved to your site. If you still intend to keep a record of entries through notification emails, then please <a href="%s" target="_blank" rel="noopener noreferrer">test your form</a> to ensure emails send reliably.', 'wpforms-lite' ),
				[
					'a' => [
						'href'   => [],
						'rel'    => [],
						'target' => [],
					],
				]
			),
			esc_url(
				wpforms_utm_link(
					'https://wpforms.com/docs/how-to-properly-test-your-wordpress-forms-before-launching-checklist/',
					'Builder Notifications',
					'Testing A Form Documentation'
				)
			)
		);

		$strings['akismet_not_installed'] = sprintf(
			wp_kses( /* translators: %1$s - link to the plugin search page, %2$s - link to the WPForms.com doc article. */
				__( 'This feature cannot be used at this time because the Akismet plugin <a href="%1$s" target="_blank" rel="noopener noreferrer">has not been installed</a>. For information on how to use this feature please <a href="%2$s" target="_blank" rel="noopener noreferrer">refer to our documentation</a>.', 'wpforms-lite' ),
				[
					'a' => [
						'href'   => [],
						'rel'    => [],
						'target' => [],
					],
				]
			),
			esc_url( admin_url( 'plugin-install.php' ) ),
			esc_url(
				wpforms_utm_link(
					'https://wpforms.com/docs/setting-up-akismet-anti-spam-protection/',
					'Builder Settings',
					'Akismet Documentation'
				)
			)
		);

		$strings['akismet_not_activated'] = sprintf(
			wp_kses( /* translators: %1$s - link to the plugins page, %2$s - link to the WPForms.com doc article. */
				__( 'This feature cannot be used at this time because the Akismet plugin <a href="%1$s" target="_blank" rel="noopener noreferrer">has not been activated</a>. For information on how to use this feature please <a href="%2$s" target="_blank" rel="noopener noreferrer">refer to our documentation</a>.', 'wpforms-lite' ),
				[
					'a' => [
						'href'   => [],
						'rel'    => [],
						'target' => [],
					],
				]
			),
			esc_url( admin_url( 'plugins.php' ) ),
			esc_url(
				wpforms_utm_link(
					'https://wpforms.com/docs/setting-up-akismet-anti-spam-protection/',
					'Builder Settings',
					'Akismet Documentation'
				)
			)
		);

		$strings['akismet_no_api_key'] = sprintf(
			wp_kses( /* translators: %1$s - link to the Akismet settings page, %2$s - link to the WPForms.com doc article. */
				__( 'This feature cannot be used at this time because the Akismet plugin <a href="%1$s" target="_blank" rel="noopener noreferrer">has not been properly configured</a>. For information on how to use this feature please <a href="%2$s" target="_blank" rel="noopener noreferrer">refer to our documentation</a>.', 'wpforms-lite' ),
				[
					'a' => [
						'href'   => [],
						'rel'    => [],
						'target' => [],
					],
				]
			),
			esc_url( admin_url( 'options-general.php?page=akismet-key-config&view=start' ) ),
			esc_url(
				wpforms_utm_link(
					'https://wpforms.com/docs/setting-up-akismet-anti-spam-protection/',
					'Builder Settings',
					'Akismet Documentation'
				)
			)
		);

		/**
		 * Form Builder localized strings filter.
		 *
		 * @since 1.8.0
		 *
		 * @param array   $strings Localized strings.
		 * @param WP_Post $form    Form object.
		 */
		$strings = (array) apply_filters( 'wpforms_builder_strings', $strings, $this->form );

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( ! empty( $_GET['form_id'] ) ) {
			$form_id = (int) $_GET['form_id'];

			$strings['preview_url'] = esc_url( add_query_arg( 'new_window', 1, wpforms_get_form_preview_url( $form_id ) ) );
			$strings['entries_url'] = esc_url( admin_url( 'admin.php?page=wpforms-entries&view=list&form_id=' . $form_id ) );
		}
		// phpcs:enable

		return $strings;
	}

	/**
	 * Footer JavaScript.
	 *
	 * @since 1.3.7
	 */
	public function footer_scripts() {

		$countries        = wpforms_countries();
		$countries_postal = array_keys( $countries );
		$countries        = array_values( $countries );

		sort( $countries_postal );
		sort( $countries );

		$choices = [
			'countries'        => [
				'name'    => esc_html__( 'Countries', 'wpforms-lite' ),
				'choices' => $countries,
			],
			'countries_postal' => [
				'name'    => esc_html__( 'Countries Postal Code', 'wpforms-lite' ),
				'choices' => $countries_postal,
			],
			'states'           => [
				'name'    => esc_html__( 'States', 'wpforms-lite' ),
				'choices' => array_values( wpforms_us_states() ),
			],
			'states_postal'    => [
				'name'    => esc_html__( 'States Postal Code', 'wpforms-lite' ),
				'choices' => array_keys( wpforms_us_states() ),
			],
			'months'           => [
				'name'    => esc_html__( 'Months', 'wpforms-lite' ),
				'choices' => array_values( wpforms_months() ),
			],
			'days'             => [
				'name'    => esc_html__( 'Days', 'wpforms-lite' ),
				'choices' => array_values( wpforms_days() ),
			],
		];

		// phpcs:disable WPForms.Comments.ParamTagHooks.InvalidParamTagsQuantity
		/**
		 * Choices preset array filter.
		 *
		 * Allows developers to edit the choices preset used in all choices-based fields.
		 *
		 * @since 1.3.7
		 *
		 * @param array $choices {
		 *    Choices presets is the [ `slug` => `preset`, ... ] array.
		 *
		 *    @param array $preset {
		 *        Each preset data is the array with two elements:
		 *
		 *        @param string $name    Name of the preset
		 *        @param array  $choices Choices array.
		 *    }
		 *    ...
		 * }
		 */
		$choices = apply_filters( 'wpforms_builder_preset_choices', $choices );
		// phpcs:enable WPForms.Comments.ParamTagHooks.InvalidParamTagsQuantity

		echo '<script type="text/javascript">wpforms_preset_choices=' . wp_json_encode( $choices ) . '</script>';

		/**
		 * Form Builder footer scripts action.
		 *
		 * @since 1.3.8
		 */
		do_action( 'wpforms_builder_print_footer_scripts' );
	}

	/**
	 * Load the appropriate files to build the page.
	 *
	 * @since 1.0.0
	 */
	public function output() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded

		if ( $this->abort ) {
			return;
		}

		/**
		 * Allow developers to disable Form Builder output.
		 *
		 * @since 1.5.8.2
		 *
		 * @param bool $is_enabled Is builder output enabled? Defaults to `true`.
		 */
		if ( ! apply_filters( 'wpforms_builder_output', true ) ) {
			return;
		}

		$form_id         = $this->form ? absint( $this->form->ID ) : '';
		$field_id        = ! empty( $this->form_data['field_id'] ) ? $this->form_data['field_id'] : '';
		$revision        = wpforms()->obj( 'revisions' )->get_revision();
		$preview_url     = wpforms_get_form_preview_url( $form_id, true );
		$allowed_caps    = [ 'edit_posts', 'edit_other_posts', 'edit_private_posts', 'edit_published_posts', 'edit_pages', 'edit_other_pages', 'edit_published_pages', 'edit_private_pages' ];
		$can_embed       = array_filter( $allowed_caps, 'current_user_can' );
		$preview_classes = [ 'wpforms-btn', 'wpforms-btn-toolbar', 'wpforms-btn-light-grey' ];
		$builder_classes = [ 'wpforms-admin-page' ];

		if ( ! $can_embed ) {
			$preview_classes[] = 'wpforms-alone';
		}

		$revision_id = null;

		if ( $revision ) {
			$revision_id       = $revision->ID;
			$builder_classes[] = 'wpforms-is-revision';
		}

		if ( $this->form && wp_revisions_enabled( $this->form ) ) {
			$builder_classes[] = 'wpforms-revisions-enabled';
		}

		/**
		 * Allow modifying builder container classes.
		 *
		 * @since 1.7.9
		 *
		 * @param array $classes   List of classes.
		 * @param array $form_data Form data and settings.
		 */
		$builder_classes = (array) apply_filters( 'wpforms_builder_output_classes', $builder_classes, $this->form_data );

		/**
		 * Allow developers to add content before the top toolbar in the Form Builder.
		 *
		 * @since 1.7.4
		 *
		 * @param string $content Content before toolbar. Defaults to empty string.
		 */
		$before_toolbar = apply_filters( 'wpforms_builder_output_before_toolbar', '' );
		?>

		<div id="wpforms-builder" class="<?php echo wpforms_sanitize_classes( $builder_classes, true ); ?>">

			<?php
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo wpforms_render( 'builder/fullscreen/ie-notice' );

			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( empty( $_GET['force_desktop_view'] ) ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				echo wpforms_render( 'builder/fullscreen/mobile-notice' );
			}
			?>

			<div id="wpforms-builder-overlay">
				<div class="wpforms-builder-overlay-content">
					<i class="spinner"></i>
					<i class="avatar"></i>
				</div>
			</div>

			<form
					name="wpforms-builder" id="wpforms-builder-form" method="post"
					data-id="<?php echo esc_attr( $form_id ); ?>"
					data-revision="<?php echo esc_attr( $revision_id ); ?>"
			>

				<input type="hidden" name="id" value="<?php echo esc_attr( $form_id ); ?>">
				<input type="hidden" value="<?php echo wpforms_validate_field_id( $field_id ); ?>" name="field_id" id="wpforms-field-id">

				<?php echo $before_toolbar; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

				<!-- Toolbar -->
				<div class="wpforms-toolbar">

					<div class="wpforms-left">
						<img src="<?php echo esc_url( WPFORMS_PLUGIN_URL . 'assets/images/sullie-alt.png' ); ?>" alt="<?php esc_attr_e( 'Sullie the WPForms mascot', 'wpforms-lite' ); ?>">
					</div>

					<div class="wpforms-center">

						<?php if ( $this->form ) : ?>

							<span class="wpforms-center-form-name-prefix">
								<?php esc_html_e( 'Now editing', 'wpforms-lite' ); ?>
							</span>

							<span class="wpforms-center-form-name wpforms-form-name">
								<?php echo esc_html( $this->form_data['settings']['form_title'] ?? $this->form->post_title ); ?>
							</span>

							<?php if ( $this->form->post_type === 'wpforms-template' ) : ?>
								<span class="wpforms-center-form-template-badge">
									<?php echo esc_html__( 'Template', 'wpforms-lite' ); ?>
								</span>
							<?php endif; ?>

						<?php endif; ?>

					</div>

					<div class="wpforms-right">

						<button id="wpforms-help"
							class="wpforms-btn wpforms-btn-toolbar wpforms-btn-light-grey"
							title="<?php esc_attr_e( 'Help Ctrl+H', 'wpforms-lite' ); ?>">
								<i class="fa fa-question-circle-o"></i>
								<span<?php echo $this->form ? ' class="screen-reader-text"' : ''; ?>>
									<?php esc_html_e( 'Help', 'wpforms-lite' ); ?>
								</span>
						</button>

						<?php if ( $this->form ) : ?>
							<div id="wpforms-context-menu-container"
								class="wpforms-btn wpforms-btn-toolbar wpforms-btn-light-grey">
								<svg width="16" height="16" fill="currentColor">
									<path d="M2 4a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm6 12a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm-6 0a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm0-6a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm6 0a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm4-8c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2ZM8 4a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm6 6a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Zm0 6a2 2 0 0 0 2-2 2 2 0 0 0-2-2 2 2 0 0 0-2 2c0 1.1.9 2 2 2Z"/>
								</svg>
								<?php echo wpforms_render( 'builder/context-menu', $this->get_context_menu_args(), true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
							</div>

							<?php if ( ! $revision ) : ?>
								<a href="<?php echo esc_url( $preview_url ); ?>"
									id="wpforms-preview-btn"
									class="<?php echo wpforms_sanitize_classes( $preview_classes, true ); ?>"
									title="<?php esc_attr_e( 'Preview Form Ctrl+P', 'wpforms-lite' ); ?>"
									target="_blank"
									rel="noopener noreferrer">
									<i class="fa fa-eye"></i><span class="text"><?php esc_html_e( 'Preview', 'wpforms-lite' ); ?></span>
								</a>
							<?php endif; ?>

							<?php if ( $can_embed && ! $revision ) : ?>
								<?php if ( $this->form->post_type === 'wpforms-template' ) : ?>
									<button id="wpforms-embed"
											class="wpforms-btn wpforms-btn-toolbar wpforms-btn-light-grey wpforms-btn-light-grey-disabled"
											title="<?php esc_attr_e( 'You cannot embed a form template', 'wpforms-lite' ); ?>">
										<i class="fa fa-code"></i><span class="text"><?php esc_html_e( 'Embed', 'wpforms-lite' ); ?></span>
									</button>
								<?php else : ?>
									<button id="wpforms-embed"
											class="wpforms-btn wpforms-btn-toolbar wpforms-btn-light-grey"
											title="<?php esc_attr_e( 'Embed Form Ctrl+B', 'wpforms-lite' ); ?>">
										<i class="fa fa-code"></i><span class="text"><?php esc_html_e( 'Embed', 'wpforms-lite' ); ?></span>
									</button>
								<?php endif; ?>
							<?php endif; ?>

							<button id="wpforms-save"
								class="wpforms-btn wpforms-btn-toolbar wpforms-btn-orange"
								title="<?php esc_attr_e( 'Save Form Ctrl+S', 'wpforms-lite' ); ?>">
									<i class="fa fa-check"></i><i class="wpforms-loading-spinner wpforms-loading-white wpforms-loading-inline wpforms-hidden"></i><span class="text"><?php esc_html_e( 'Save', 'wpforms-lite' ); ?></span>
							</button>

						<?php endif; ?>

						<button id="wpforms-exit" title="<?php esc_attr_e( 'Exit Ctrl+Q', 'wpforms-lite' ); ?>">
							<i class="fa fa-times"></i>
						</button>

					</div>

				</div>

				<!-- Panel toggle buttons. -->
				<div class="wpforms-panels-toggle" id="wpforms-panels-toggle">

					<?php
					/**
					 * Outputs the buttons to toggle between Form Builder panels.
					 *
					 * @since 1.0.0
					 *
					 * @param WP_Post $form The form object.
					 * @param string  $view Current view (panel) name.
					 */
					do_action( 'wpforms_builder_panel_buttons', $this->form, $this->view );
					?>

				</div>

				<div class="wpforms-panels">

					<?php
					/**
					 * Outputs the contents of Form Builder panels.
					 *
					 * @since 1.0.0
					 *
					 * @param WP_Post $form The form object.
					 * @param string  $view Current view (panel) name.
					 */
					do_action( 'wpforms_builder_panels', $this->form, $this->view );
					?>

				</div>

			</form>

		</div>

		<?php
	}

	/**
	 * Display an abort message using empty state page.
	 *
	 * @since 1.7.3
	 */
	public function display_abort_message() {

		if ( ! $this->abort ) {
			return;
		}

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo wpforms_render(
			'builder/fullscreen/abort-message',
			[
				'message' => $this->abort_message,
			],
			true
		);
	}

	/**
	 * Change default admin meta viewport tag upon request to force scrollable
	 * desktop view on small screens.
	 *
	 * @since 1.7.8
	 *
	 * @param string|mixed $value Default meta viewport tag value.
	 *
	 * @return string
	 */
	public function viewport_meta( $value ): string {

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( ! empty( $_GET['force_desktop_view'] ) ) {
			return 'width=1024, initial-scale=1';
		}

		return (string) $value;
	}

	/**
	 * Get localized currency strings for the builder.
	 *
	 * @since 1.8.2
	 *
	 * @param array $strings Array of localized strings.
	 *
	 * @return array
	 */
	private function add_localized_currencies( array $strings ): array {

		$currency   = wpforms_get_currency();
		$currencies = wpforms_get_currencies();

		$strings['currency']            = sanitize_text_field( $currency );
		$strings['currency_name']       = isset( $currencies[ $currency ]['name'] ) ? sanitize_text_field( $currencies[ $currency ]['name'] ) : '';
		$strings['currency_decimals']   = wpforms_get_currency_decimals( $currencies[ $currency ] );
		$strings['currency_decimal']    = isset( $currencies[ $currency ]['decimal_separator'] ) ? sanitize_text_field( $currencies[ $currency ]['decimal_separator'] ) : '.';
		$strings['currency_thousands']  = isset( $currencies[ $currency ]['thousands_separator'] ) ? sanitize_text_field( $currencies[ $currency ]['thousands_separator'] ) : ',';
		$strings['currency_symbol']     = isset( $currencies[ $currency ]['symbol'] ) ? sanitize_text_field( $currencies[ $currency ]['symbol'] ) : '$';
		$strings['currency_symbol_pos'] = isset( $currencies[ $currency ]['symbol_pos'] ) ? sanitize_text_field( $currencies[ $currency ]['symbol_pos'] ) : 'left';

		return $strings;
	}

	/**
	 * Get context menu arguments, depending on the Lite/Pro version and form or form template type.
	 *
	 * @since 1.8.8
	 *
	 * @return array
	 */
	private function get_context_menu_args(): array {

		$args = [
			'form_id'          => $this->form->ID,
			'is_form_template' => $this->form->post_type === 'wpforms-template',
			'has_payments'     => wpforms()->obj( 'payment' )->get_by( 'form_id', $this->form->ID ) !== null,
			'show_whats_new'   => wpforms()->obj( 'splash_screen' )->is_available_for_display(),
		];

		if ( wpforms()->is_pro() ) {
			$args['has_entries']   = wpforms()->obj( 'entry' )->get_entries( [ 'form_id' => $this->form->ID ], true ) > 0;
			$args['can_duplicate'] = $this->can_duplicate();
		}

		return $args;
	}

	/**
	 * Check if the current user is allowed to duplicate the form.
	 *
	 * @since 1.8.8
	 *
	 * @return bool
	 */
	private function can_duplicate(): bool {

		if ( ! wpforms_current_user_can( 'create_forms' ) ) {
			return false;
		}

		if ( ! wpforms_current_user_can( 'view_form_single', $this->form->ID ) ) {
			return false;
		}

		return true;
	}
}

WPForms_Builder::instance();
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!