is_admin = ( is_admin() && ! wp_doing_ajax() ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST );
$this->init();
}
/**
* Init method
*
* @since 1.0
*/
public function init() {
add_shortcode( 'forminator_' . static::$module_slug, array( $this, 'render_shortcode' ) );
}
/**
* Render shortcode
*
* @since 1.0
*
* @param array $atts Attributes.
*
* @return string
*/
public function render_shortcode( $atts = array() ) {
// use already created instance if already available.
$view = new static();
$id = ! empty( $atts['id'] ) ? (string) (int) $atts['id'] : 0;
if ( ! $id ) {
return $view->message_required();
}
$is_preview = isset( $atts['is_preview'] ) ? $atts['is_preview'] : false;
$is_preview = filter_var( $is_preview, FILTER_VALIDATE_BOOLEAN );
if ( false === $is_preview && forminator_is_page_builder_preview() ) {
$is_preview = true;
}
$is_preview = apply_filters( 'forminator_render_shortcode_is_preview', $is_preview );
$preview_data = isset( $atts['preview_data'] ) ? $atts['preview_data'] : array();
$is_block_editor = isset( $atts['is_block_editor'] ) ? $atts['is_block_editor'] : false;
ob_start();
$view->display( $id, $is_preview, $preview_data );
$lead_data = ! empty( static::$lead_data ) ? static::$lead_data : array();
$view->ajax_loader( $is_preview, $preview_data, $lead_data, $is_block_editor );
return ob_get_clean();
}
/**
* Display form method
* Must be implemented by class that extend it
*
* @since 1.0
*
* @param int $id Id.
* @param bool $is_preview Is preview.
*
* @return mixed
*/
abstract public function display( $id, $is_preview = false );
/**
* Generate render_id for current form
* represented as integer, start from 0
*
* @param int $id Module id.
* @param ?int $forced_render_id Optional. The render id to force for module id.
*/
public function generate_render_id( $id, $forced_render_id = null ) {
// set render_id for mapping Front End with its form.
if ( ! is_numeric( $forced_render_id ) ) {
if ( ! isset( self::$render_ids[ $id ] ) ) {
self::$render_ids[ $id ] = 0;
} else {
++self::$render_ids[ $id ];
}
} else {
self::$render_ids[ $id ] = intval( $forced_render_id );
}
// Add other plugin classes here that causes additional render_id.
if ( self::$render_ids[ $id ] > 0 && class_exists( 'DiviOverlaysCore' ) ) {
--self::$render_ids[ $id ];
}
}
/**
* Render form markup
*
* @since 1.0
*
* @param int $id Id.
* @param bool $hide If true, display: none will be added on the form markup and later removed with JS.
* @param bool $is_preview Is preview.
* @param int $render_id Render Id.
*/
public function render( $id, $hide = true, $is_preview = false, $render_id = 0 ) {
$form_type = $this->get_form_type();
$form_fields = $this->get_fields();
$form_settings = $this->get_form_settings();
$post_id = $this->get_post_id();
$this->is_preview = $is_preview;
do_action( 'forminator_before_form_render', $id, $form_type, $post_id, $form_fields, $form_settings );
$this->get_form( $id, true, $hide, $render_id );
do_action( 'forminator_after_form_render', $id, $form_type, $post_id, $form_fields, $form_settings );
}
/**
* Maybe wrap description
*
* @param string $html HTML.
* @param string $description Description.
* @param string $id ID.
* @param string $descr_position Description position.
*
* @return string
*/
public function maybe_wrap_description( $html, $description, $id, $descr_position ) {
if ( empty( $html ) ) {
return $html;
}
if ( 'above' === $descr_position && 'none' === $this->get_form_design() ) {
$html = '
' . $html . '
';
}
return $html;
}
/**
* Return form markup
*
* @since 1.0
*
* @param int $id Id.
* @param bool $render Render.
* @param bool $hide Hide.
* @param int $render_id_ajax Render id.
*
* @return mixed|void
*/
public function get_form( $id, $render = true, $hide = true, $render_id_ajax = 0 ) {
$id = (int) $id;
$html = '';
$forminator_ui = '';
$maybe_draft = '';
$form_type = $this->get_form_type();
$form_fields = $this->get_fields();
$form_settings = $this->get_form_settings();
$form_design = $this->get_form_design();
$extra_attrs = $this->form_enctype();
$extra_classes = $this->form_extra_classes();
$track_views = $this->can_track_views();
$fields_type_class = $this->get_fields_type_class();
$design_class = $this->get_form_design_class();
$form_uid = 'data-uid="' . esc_attr( self::$uid ) . '"';
// If rendered on Preview, the array is empty and sometimes PHP notices show up.
if ( $this->is_admin && ( empty( self::$render_ids ) || ! $id ) ) {
self::$render_ids[ $id ] = 0;
}
if ( isset( $form_settings['use_ajax_load'] ) && empty( $form_settings['use_ajax_load'] ) ) {
$render_id = self::$render_ids[ $id ];
} else {
$render_id = $render_id_ajax;
}
$forminator_ui = 'forminator-ui ';
if ( ! empty( $form_settings['cform-color-option'] ) && 'theme' === $form_settings['cform-color-option'] ) {
$extra_attrs .= ' data-color-option="theme"';
} else {
$extra_attrs .= ' data-color-option="default"';
}
if ( 'quiz' === $form_type ) {
$extra_attrs .= ' data-design="' . $this->get_quiz_theme() . '"';
} else {
$extra_attrs .= ' data-design="' . $this->get_form_design() . '"';
}
if ( 'custom-form' === $form_type ) {
$is_draft_enabled = isset( $form_settings['use_save_and_continue'] ) ? filter_var( $form_settings['use_save_and_continue'], FILTER_VALIDATE_BOOLEAN ) : false;
$maybe_draft = $this->set_draft_data( $is_draft_enabled );
$extra_attrs .= ' data-grid="' . $this->get_fields_style() . '"';
if ( $is_draft_enabled ) {
$extra_classes .= ' draft-enabled';
}
if ( ! empty( $form_settings['abandonment'] ) ) {
$extra_classes .= ' forminator-tracking-abandonment';
$extra_attrs .= $this->get_abandonment_required_fields();
}
if ( $this->has_pagination() ) {
$extra_attrs .= $this->get_draft_page();
}
add_filter( 'forminator_field_description', array( $this, 'maybe_wrap_description' ), 10, 4 );
}
// Markup Loader.
$loader = sprintf(
'
',
$forminator_ui,
$form_type,
$form_type,
$id,
$design_class,
$fields_type_class,
$extra_classes,
$render_id,
$id,
$form_uid
);
// To-Do: Remove when live preview for Poll & Quiz implemented.
if ( 'custom-form' !== $form_type ) {
$loader = '';
}
if ( 'quiz' === $form_type ) {
$quiz_type = $this->model->quiz_type;
$extra_attrs .= ' data-quiz="' . $quiz_type . '"';
$extra_attrs .= ' aria-live="polite"'; // Listen to live changes on form.
if ( isset( $form_settings['quiz-spacing'] ) && ! empty( $form_settings['quiz-spacing'] ) ) {
$extra_attrs .= ' data-spacing="' . $form_settings['quiz-spacing'] . '"';
} else {
$extra_attrs .= ' data-spacing="default"';
}
if ( isset( $form_settings['quiz-alignment'] ) && ! empty( $form_settings['quiz-alignment'] ) ) {
$extra_attrs .= ' data-alignment="' . $form_settings['quiz-alignment'] . '"';
} elseif ( false !== strpos( $form_design, 'grid' ) ) {
$extra_attrs .= ' data-alignment="center"';
} else {
$extra_attrs .= ' data-alignment="left"';
}
if ( isset( $form_settings['visual_style'] ) && 'grid' === $form_settings['visual_style'] ) {
if ( isset( $form_settings['quiz-grid-cols'] ) ) {
$extra_attrs .= ' data-columns="' . $form_settings['quiz-grid-cols'] . '"';
} else {
$extra_attrs .= ' data-columns="3"';
}
}
}
$has_lead = isset( $form_settings['hasLeads'] ) ? $form_settings['hasLeads'] : false;
$html .= $loader;
if ( $hide && ! $this->is_preview && ! is_admin() ) {
$extra_attrs .= ' style="display: none;"';
}
if ( 'quiz' === $form_type && $has_lead ) {
$html .= $this->render_form_header();
}
$html .= sprintf(
'' );
if ( 'custom-form' === $form_type ) {
$html .= $this->render_skip_form_content();
}
// Add edit module link.
$html .= $this->edit_module_link( $id, $form_type, $this->is_preview );
if ( $track_views && empty( $this->draft_data ) ) {
$form_view = Forminator_Form_Views_Model::get_instance();
$post_id = $this->get_post_id();
if ( ! $this->is_admin && forminator_global_tracking() ) {
$form_view->save_view( $id, $post_id );
}
}
if ( $render ) {
echo apply_filters( 'forminator_render_form_markup', $html, $form_fields, $form_type, $form_settings, $form_design, $render_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
/* @noinspection PhpInconsistentReturnPointsInspection */
return apply_filters( 'forminator_render_form_markup', $html, $form_fields, $form_type, $form_settings, $form_design, $render_id );
}
}
/**
* Refresh nonce to avoid static cache
*/
private function add_script_for_refresh_nonce() {
if ( empty( $this->model->settings['use_ajax_load'] ) || '1' !== $this->model->settings['use_ajax_load'] ) {
$form_id = $this->model->id;
add_action(
'wp_footer',
function () use ( $form_id ) {
echo '';
},
99
);
}
}
/**
* Return form placeholder markup
*
* @since 1.6.1
*
* @param int $id Id.
* @param bool $render Render.
*
* @return mixed|void
*/
public function get_form_placeholder( $id, $render = true ) {
$html = '';
$id = (int) $id;
$form_type = $this->get_form_type();
// if rendered on Preview, the array is empty and sometimes PHP notices show up.
if ( $this->is_admin && ( empty( self::$render_ids ) || ! $id ) ) {
self::$render_ids[ $id ] = 0;
}
$render_id = self::$render_ids[ $id ];
$form_uid = 'data-uid="' . esc_attr( self::$uid ) . '"';
$html .= sprintf(
'';
if ( $render ) {
echo apply_filters( 'forminator_render_form_placeholder_markup', $html, $form_type, $render_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
/* @noinspection PhpInconsistentReturnPointsInspection */
return apply_filters( 'forminator_render_form_placeholder_markup', $html, $form_type, $render_id );
}
}
/**
* Get Additional CSS class to be aplied based on fields style (enclosed or not)
*
* @since 1.0.5
* @return string
*/
public function get_fields_type_class() {
$form_type = $this->get_form_type();
$fields_style = $this->get_fields_style();
if ( 'custom-form' === $form_type ) {
if ( 'open' !== $fields_style ) {
$fields_type = 'forminator-' . $fields_style;
} else {
$fields_type = '';
}
} else {
$fields_type = '';
}
/**
* Filter CSS of fields_type that will be added on user
*
* @since 1.0.5
*
* @param string $fields_type current fields type CSS class that aplied.
* @param string $form_type (custom-form / poll / quiz).
* @param string $fields_style (enclosed ?).
*/
return apply_filters( 'forminator_render_fields_type_class', $fields_type, $form_type, $fields_style );
}
/**
* Get Additional CSS class to be aplied based on get_form_design
*
* @since 1.0.5
* @return string
*/
public function get_form_design_class() {
$form_type = $this->get_form_type();
$form_design = $this->get_form_design();
if ( 'quiz' === $form_type ) {
$design_class = 'forminator-quiz--' . $form_design;
} elseif ( 'none' === $form_design ) {
$design_class = '';
} else {
$design_class = 'forminator-design--' . $form_design;
}
/**
* Filter design CSS class that will be aplied on