register_block_from_metadata( 'submit' );
}
public function render( $atts, $content, $block = null ) {
$form_id = $this->resolve_form_scope_id();
$dynamic_target_post_id = 0;
if ( $form_id && function_exists( 'stacklar_multilingual' ) ) {
$atts = stacklar_multilingual()->translate_block_attributes( $form_id, 'stacklar/submit', is_array( $atts ) ? $atts : array() );
}
$submit_post_settings = $form_id ? stacklar_get_action_settings_for_action( $form_id, 'stacklar_submit_post' ) : array();
$edit_link_enabled = ! empty( $submit_post_settings ) && isset( $submit_post_settings['editlinkenabled'] )
? stacklar_is_truthy( $submit_post_settings['editlinkenabled'] )
: false;
if ( $edit_link_enabled ) {
if ( ! function_exists( 'is_user_logged_in' ) || ! is_user_logged_in() ) {
return $this->render_access_message( __( 'Please log in to edit this content.', 'stacklar-forms' ) );
}
$roles = isset( $submit_post_settings['editlinkroles'] ) ? stacklar_parse_role_list( $submit_post_settings['editlinkroles'] ) : array();
if ( ! stacklar_current_user_has_role( $roles ) ) {
return $this->render_access_message( __( 'You do not have permission to edit this content.', 'stacklar-forms' ) );
}
// The post to edit comes from the edit link; edit_post is checked below.
$target_post_id = isset( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( $target_post_id ) {
if ( ! current_user_can( 'edit_post', $target_post_id ) ) {
return $this->render_access_message( __( 'You do not have permission to edit this content.', 'stacklar-forms' ) );
}
$dynamic_target_post_id = $target_post_id;
} else {
if ( ! current_user_can( 'edit_posts' ) ) {
return $this->render_access_message( __( 'You do not have permission to edit this content.', 'stacklar-forms' ) );
}
}
}
if ( ! $dynamic_target_post_id && function_exists( 'get_queried_object' ) ) {
$queried_object = get_queried_object();
if ( $queried_object instanceof WP_Post ) {
$dynamic_target_post_id = absint( $queried_object->ID );
}
}
if ( ! $dynamic_target_post_id && function_exists( 'get_the_ID' ) ) {
$dynamic_target_post_id = absint( get_the_ID() );
}
$scope_class = $form_id ? ' stacklar--' . $form_id : '';
$submit_label = isset( $atts['submitLabel'] ) ? $atts['submitLabel'] : 'Submit';
$test_mode = $form_id && function_exists( 'stacklar_is_form_test_mode' )
? stacklar_is_form_test_mode( $form_id )
: ! empty( $atts['testMode'] );
$actions = $this->prepare_actions( $atts );
$action_settings = $this->prepare_action_settings( $atts );
if ( $this->should_store_entries( $atts ) && ! in_array( 'stacklar_save_entry', $actions, true ) ) {
array_unshift( $actions, 'stacklar_save_entry' );
}
$actions = array_values( array_unique( $actions ) );
$paypal_enabled = in_array( 'stacklar_paypal', $actions, true );
$stripe_enabled = in_array( 'stacklar_stripe', $actions, true );
$woocommerce_enabled = in_array( 'stacklar_woocommerce', $actions, true );
$protection_config = function_exists( 'stacklar_submission_protection_service' )
? stacklar_submission_protection_service()->get_render_config( $form_id )
: array( 'enabled' => false );
$restrictions_config = function_exists( 'stacklar_restrictions_service' )
? stacklar_restrictions_service()->get_render_config( $form_id )
: array( 'enabled' => false );
$survey_results_config = function_exists( 'stacklar_survey_results_service' )
? stacklar_survey_results_service()->get_render_config( $form_id )
: array( 'enabled' => false );
$partial_config = class_exists( 'Stacklar_Abandonments', false )
? Stacklar_Abandonments::get_render_config( $form_id )
: array( 'enabled' => false );
$autosave_nonce = $form_id ? wp_create_nonce( 'stacklar_autosave_' . $form_id ) : '';
$config_nonce = $form_id ? wp_create_nonce( 'stacklar_config_' . $form_id ) : '';
$dynamic_post_context = $form_id && $dynamic_target_post_id && function_exists( 'stacklar_create_dynamic_post_context' )
? stacklar_create_dynamic_post_context( $form_id, $dynamic_target_post_id )
: array();
$form_typography = '';
if ( ! empty( $atts['style'] ) && ! empty( $atts['style']['typography'] ) && function_exists( 'wp_style_engine_get_styles' ) ) {
$typo_result = wp_style_engine_get_styles( array( 'typography' => $atts['style']['typography'] ) );
if ( ! empty( $typo_result['css'] ) ) {
$form_typography = implode( ' ', stacklar_sanitize_css_declarations( array( $typo_result['css'] ) ) );
}
}
$button_styles = $this->build_button_style( $atts );
$wrap_styles = $this->build_wrap_style(
$this->resolve_responsive_scalar_style_value( $atts, 'submitAlign', 'desktop', 'string' ),
isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null
);
$has_steps = $this->form_has_step_blocks( $form_id );
$is_multistep = $has_steps;
if ( ! $has_steps && ! $form_id ) {
$is_multistep = ! empty( $atts['isMultiStep'] );
}
$show_progress = ! empty( $atts['showProgressBar'] );
$progress_color = $atts['progressBarColor'] ?? '#111111';
$progress_bg = $atts['progressBarBg'] ?? '#e2e8f0';
$progress_height = isset( $atts['progressBarHeight'] ) ? intval( $atts['progressBarHeight'] ) : 6;
$progress_percent = isset( $atts['progressShowPercent'] ) ? (bool) $atts['progressShowPercent'] : true;
$progress_aria = $atts['progressAriaLabel'] ?? 'Form progress';
$form_classes = trim( 'stacklar' . $scope_class . ( $is_multistep ? ' is-multistep' : '' ) );
$form_instance_id = wp_unique_id( 'stacklar-' );
$instance_selector = '.stacklar-submit-root[data-stacklar-instance="' . esc_attr( $form_instance_id ) . '"]';
$partial_active = ! empty( $partial_config['enabled'] ) && ! empty( $partial_config['licenseValid'] );
$partial_autosave = $partial_active && ! empty( $partial_config['autosaveEnabled'] );
$partial_client = $partial_active && ( $partial_autosave || ! empty( $partial_config['showSaveButton'] ) || ! empty( $partial_config['resumeEnabled'] ) );
$current_locale = $form_id && function_exists( 'stacklar_get_current_locale' ) ? stacklar_get_current_locale( $form_id ) : '';
$form_attrs = 'id="' . esc_attr( $form_instance_id ) . '" data-stacklar-instance="' . esc_attr( $form_instance_id ) . '" class="' . esc_attr( $form_classes ) . '" method="post" data-stacklar-rest="1" data-stacklar-abandonment="' . ( $partial_client ? '1' : '0' ) . '"';
if ( '' !== $current_locale ) {
$form_attrs .= ' data-stacklar-locale="' . esc_attr( $current_locale ) . '"';
}
if ( $test_mode ) {
$form_attrs .= ' data-stacklar-test-mode="1"';
}
if ( $form_id ) {
$form_attrs .= ' data-stacklar-id="' . esc_attr( $form_id ) . '"';
}
if ( $paypal_enabled ) {
$form_attrs .= ' data-stacklar-paypal="1"';
}
if ( $stripe_enabled ) {
$form_attrs .= ' data-stacklar-stripe="1"';
}
if ( $woocommerce_enabled ) {
$form_attrs .= ' data-stacklar-woocommerce="1"';
}
if ( $form_typography !== '' ) {
$form_attrs .= ' style="' . esc_attr( $form_typography ) . '"';
}
if ( ! empty( $atts['useLabelKeys'] ) ) {
$form_attrs .= ' data-stacklar-label-keys="1"';
} else {
$form_attrs .= ' data-stacklar-label-keys="0"';
}
$form_attrs .= ' data-stacklar-autosave-token=""';
$form_attrs .= ' data-stacklar-autosave-nonce="' . esc_attr( $autosave_nonce ) . '"';
if ( ! empty( $partial_config['enabled'] ) ) {
$form_attrs .= ' data-stacklar-partial="1"';
$form_attrs .= ' data-stacklar-partial-autosave="' . ( $partial_autosave ? '1' : '0' ) . '"';
$form_attrs .= ' data-stacklar-autosave-interval="' . esc_attr( isset( $partial_config['autosaveIntervalSeconds'] ) ? absint( $partial_config['autosaveIntervalSeconds'] ) : 15 ) . '"';
$form_attrs .= ' data-stacklar-partial-resume="' . ( ! empty( $partial_config['resumeEnabled'] ) ? '1' : '0' ) . '"';
$form_attrs .= ' data-stacklar-partial-save-message="' . esc_attr( isset( $partial_config['savedMessage'] ) ? $partial_config['savedMessage'] : '' ) . '"';
$form_attrs .= ' data-stacklar-partial-resume-message="' . esc_attr( isset( $partial_config['resumeMessage'] ) ? $partial_config['resumeMessage'] : '' ) . '"';
$form_attrs .= ' data-stacklar-partial-expired-message="' . esc_attr( isset( $partial_config['expiredMessage'] ) ? $partial_config['expiredMessage'] : '' ) . '"';
}
$hidden_inputs = '';
if ( $form_id ) {
$hidden_inputs .= '';
if ( '' !== $current_locale ) {
$hidden_inputs .= '';
}
if ( $config_nonce ) {
$hidden_inputs .= '';
}
if ( ! empty( $dynamic_post_context['post_id'] ) && ! empty( $dynamic_post_context['expires'] ) && ! empty( $dynamic_post_context['signature'] ) ) {
$hidden_inputs .= '';
$hidden_inputs .= '';
$hidden_inputs .= '';
}
$hidden_inputs .= '';
$hidden_inputs .= '';
if ( ! empty( $protection_config['enabled'] ) || ! empty( $restrictions_config['enabled'] ) || ! empty( $survey_results_config['enabled'] ) || ! empty( $partial_config['enabled'] ) ) {
$hidden_inputs .= '';
}
if ( ! empty( $protection_config['enabled'] ) ) {
if ( ! empty( $protection_config['issued_at'] ) && ! empty( $protection_config['signature'] ) ) {
$hidden_inputs .= '';
$hidden_inputs .= '';
}
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- carries the edit link's post ID into the form.
if ( $edit_link_enabled && isset( $_GET['post_id'] ) ) {
$edit_post_id = absint( $_GET['post_id'] );
// phpcs:enable WordPress.Security.NonceVerification.Recommended
if ( $edit_post_id ) {
$hidden_inputs .= '';
}
}
}
$html = '
';
$html .= '
';
$html .= '
';
$prepended_css = '';
if ( $is_multistep ) {
$multistep_css = $this->build_multistep_css( $atts, $form_id );
if ( $multistep_css ) {
$prepended_css .= $multistep_css;
}
} else {
$hover_css = $this->build_hover_css( $atts, $form_id );
$focus_css = $this->build_focus_css( $atts, $form_id );
$style = '';
if ( $hover_css ) $style .= $hover_css;
if ( $focus_css ) $style .= $focus_css;
if ( $style !== '' ) {
$prepended_css .= $style;
}
}
$message_css = $this->build_message_css( $atts, $form_id );
if ( $message_css ) {
$prepended_css .= $message_css;
}
$responsive_submit_css = $this->build_submit_responsive_css( $atts, $instance_selector );
if ( $responsive_submit_css ) {
$prepended_css .= $responsive_submit_css;
}
stacklar_add_inline_css( $prepended_css );
return $html;
}
protected function prepare_actions( $atts ) {
$actions = array();
if ( ! empty( $atts['actions'] ) && is_array( $atts['actions'] ) ) {
foreach ( $atts['actions'] as $act ) {
$act = sanitize_key( $act );
if ( $act ) {
$actions[] = $act;
}
}
}
return array_values( array_unique( $actions ) );
}
protected function prepare_action_settings( $atts ) {
$out = array();
if ( empty( $atts['actionSettings'] ) || ! is_array( $atts['actionSettings'] ) ) {
return $out;
}
foreach ( $atts['actionSettings'] as $slug => $settings ) {
$slug_key = sanitize_key( $slug );
if ( ! $slug_key || ! is_array( $settings ) ) {
continue;
}
foreach ( $settings as $key => $value ) {
$setting_key = sanitize_key( $key );
if ( '' === $setting_key ) {
continue;
}
if ( is_scalar( $value ) ) {
$out[ $slug_key ][ $setting_key ] = sanitize_text_field( $value );
}
}
}
return $out;
}
protected function should_track_abandonment( $atts, $form_id = 0 ) {
if ( $form_id && class_exists( 'Stacklar_Abandonments', false ) ) {
return Stacklar_Abandonments::is_autosave_enabled( $form_id );
}
if ( array_key_exists( 'trackAbandonment', $atts ) ) {
return (bool) $atts['trackAbandonment'];
}
return false;
}
protected function render_access_message( $message ) {
$message = is_string( $message ) ? $message : '';
if ( '' === $message ) {
return '';
}
return '' . esc_html( $message ) . '
';
}
protected function should_store_entries( $atts ) {
if ( array_key_exists( 'storeEntries', $atts ) ) {
return (bool) $atts['storeEntries'];
}
return false;
}
protected function build_wrap_style( $align, $button_margin = null, $device = 'desktop', $force_explicit_margin_top = false ) {
$align = $align ? sanitize_key( $align ) : 'left';
$styles = array();
if ( 'center' === $align ) {
$styles[] = 'display:flex;';
$styles[] = 'justify-content:center;';
} elseif ( 'right' === $align ) {
$styles[] = 'display:flex;';
$styles[] = 'justify-content:flex-end;';
} elseif ( 'full' === $align ) {
$styles[] = 'display:block;';
} else {
$styles[] = 'display:flex;';
$styles[] = 'justify-content:flex-start;';
}
if ( $force_explicit_margin_top ) {
$styles[] = $this->has_box_side_value( $button_margin, 'top', $device ) ? 'margin-top:0;' : 'margin-top:8px;';
} elseif ( ! $this->has_box_side_value( $button_margin, 'top', $device ) ) {
$styles[] = 'margin-top:8px;';
}
return $styles;
}
protected function resolve_padding_css( $atts, $device = 'desktop' ) {
$pad = isset( $atts['submitPadding'] ) ? $this->resolve_responsive_style_value( $atts['submitPadding'], $device, 'box' ) : null;
$pad_y = isset( $atts['submitPadY'] ) ? floatval( $atts['submitPadY'] ) : 8;
$pad_x = isset( $atts['submitPadX'] ) ? floatval( $atts['submitPadX'] ) : 12;
if ( is_string( $pad ) ) {
$pad = trim( $pad );
if ( '' !== $pad ) {
return $pad;
}
}
if ( is_array( $pad ) && ! empty( $pad ) ) {
$unit = ! empty( $pad['unit'] ) ? preg_replace( '/[^a-z%]/i', '', $pad['unit'] ) : 'px';
$format = function( $value, $fallback ) use ( $unit ) {
if ( $value === null || $value === '' ) {
return $fallback === 0 ? '0' : ( preg_match( '/[a-z%]+$/i', (string) $fallback ) ? $fallback : $fallback . $unit );
}
$str = is_string( $value ) ? trim( $value ) : ( is_numeric( $value ) ? (string) $value : '' );
if ( '' === $str ) {
return '0';
}
return preg_match( '/[a-z%]+$/i', $str ) ? $str : $str . $unit;
};
return $format( $pad['top'] ?? '', $pad_y ) . ' '
. $format( $pad['right'] ?? '', $pad_x ) . ' '
. $format( $pad['bottom'] ?? '', $pad_y ) . ' '
. $format( $pad['left'] ?? '', $pad_x );
}
return $pad_y . 'px ' . $pad_x . 'px';
}
protected function resolve_box_css( $box, $device = 'desktop' ) {
$box = $this->resolve_responsive_style_value( $box, $device, 'box' );
if ( is_string( $box ) ) {
return trim( $box );
}
if ( empty( $box ) || ! is_array( $box ) ) {
return '';
}
$has_value = false;
foreach ( array( 'top', 'right', 'bottom', 'left' ) as $side ) {
if ( isset( $box[ $side ] ) && trim( (string) $box[ $side ] ) !== '' ) {
$has_value = true;
break;
}
}
if ( ! $has_value ) {
return '';
}
$unit = ! empty( $box['unit'] ) ? preg_replace( '/[^a-z%]/i', '', $box['unit'] ) : 'px';
$format = function( $value ) use ( $unit ) {
if ( $value === null || $value === '' ) {
return '0';
}
$str = is_string( $value ) ? trim( $value ) : ( is_numeric( $value ) ? (string) $value : '' );
if ( '' === $str ) {
return '0';
}
return preg_match( '/[a-z%]+$/i', $str ) ? $str : $str . $unit;
};
return $format( $box['top'] ?? '' ) . ' '
. $format( $box['right'] ?? '' ) . ' '
. $format( $box['bottom'] ?? '' ) . ' '
. $format( $box['left'] ?? '' );
}
protected function has_box_side_value( $box, $side, $device = 'desktop' ) {
$box = $this->resolve_responsive_style_value( $box, $device, 'box' );
if ( empty( $box ) || ! is_array( $box ) || ! isset( $box[ $side ] ) ) {
return false;
}
$value = is_scalar( $box[ $side ] ) ? trim( (string) $box[ $side ] ) : '';
return '' !== $value;
}
protected function build_typography_declarations( $value, $context = 'attr', $device = 'desktop' ) {
$value = $this->resolve_responsive_style_value( $value, $device, 'typography' );
if ( empty( $value ) || ! is_array( $value ) ) {
return array();
}
if ( isset( $value['typography'] ) && is_array( $value['typography'] ) ) {
$value = $value['typography'];
}
$map = array(
'fontFamily' => 'font-family',
'fontSize' => 'font-size',
'fontStyle' => 'font-style',
'fontWeight' => 'font-weight',
'lineHeight' => 'line-height',
'letterSpacing' => 'letter-spacing',
'textTransform' => 'text-transform',
'textDecoration'=> 'text-decoration',
'textAlign' => 'text-align',
);
$styles = array();
foreach ( $map as $key => $property ) {
if ( ! isset( $value[ $key ] ) ) {
continue;
}
$raw = $value[ $key ];
if ( $raw === '' || $raw === null ) {
continue;
}
$sanitized = is_scalar( $raw ) ? trim( wp_strip_all_tags( (string) $raw ) ) : '';
if ( '' === $sanitized ) {
continue;
}
$styles[] = $property . ':' . stacklar_sanitize_css_value( $sanitized ) . ';';
}
return $styles;
}
protected function sanitize_css_keyword( $value ) {
return preg_replace( '/[^a-z-]/i', '', (string) $value );
}
protected function clamp_css_number( $value, $min = 0, $max = null ) {
$number = floatval( $value );
if ( null !== $min ) {
$number = max( floatval( $min ), $number );
}
if ( null !== $max ) {
$number = min( floatval( $max ), $number );
}
return $number;
}
protected function append_css_rule_if_string( array &$rules, $property, $value, $important = false ) {
$value = trim( (string) $value );
if ( '' === $value ) {
return;
}
$rules[] = $property . ':' . stacklar_sanitize_css_value( $value ) . ( $important ? ' !important' : '' ) . ';';
}
protected function append_css_rule_if_number( array &$rules, $property, $value, $unit = 'px', $min = 0, $max = null, $important = false ) {
if ( null === $value ) {
return;
}
$rules[] = $property . ':' . $this->clamp_css_number( $value, $min, $max ) . $unit . ( $important ? ' !important' : '' ) . ';';
}
protected function append_resolved_string_rule( array &$rules, $atts, $key, $property, $device = 'desktop', $important = false, $keyword = false, $responsive_only = false ) {
if ( $responsive_only && ! $this->has_responsive_scalar_style_value( $atts, $key, 'string' ) ) {
return;
}
$value = $this->resolve_responsive_scalar_style_value( $atts, $key, $device, 'string' );
$value = $keyword ? $this->sanitize_css_keyword( $value ) : trim( (string) $value );
$this->append_css_rule_if_string( $rules, $property, $value, $important );
}
protected function append_resolved_number_rule( array &$rules, $atts, $key, $property, $device = 'desktop', $unit = 'px', $min = 0, $max = null, $important = false, $responsive_only = false ) {
if ( $responsive_only && ! $this->has_responsive_scalar_style_value( $atts, $key, 'number' ) ) {
return;
}
$value = $this->resolve_responsive_scalar_style_value( $atts, $key, $device, 'number' );
$this->append_css_rule_if_number( $rules, $property, $value, $unit, $min, $max, $important );
}
protected function build_button_style( $atts, $device = 'desktop' ) {
$styles = array();
$styles[] = 'box-sizing:border-box;';
$styles[] = 'box-shadow:none;';
$styles[] = 'font-family:inherit;';
$styles[] = 'font-size:16px;';
$styles[] = 'font-weight:400;';
$styles[] = 'line-height:1.2;';
$styles[] = 'text-align:center;';
$styles[] = 'text-decoration:none;';
$styles[] = 'appearance:none;';
$submit_bg = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBg', $device, 'string' ) );
if ( $submit_bg !== '' ) {
$styles[] = 'background:' . stacklar_sanitize_css_value( $submit_bg ) . ';';
}
$submit_color = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitColor', $device, 'string' ) );
if ( $submit_color !== '' ) {
$styles[] = 'color:' . stacklar_sanitize_css_value( $submit_color ) . ';';
}
$border_width_value = $this->resolve_responsive_scalar_style_value( $atts, 'submitBorderWidth', $device, 'number' );
$border_width = $border_width_value !== null ? max( 0, floatval( $border_width_value ) ) : 1;
$border_style = preg_replace( '/[^a-z-]/i', '', (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBorderStyle', $device, 'string' ) );
$border_style = $border_style !== '' ? $border_style : 'solid';
$border_color = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBorder', $device, 'string' ) );
$border_color = stacklar_sanitize_css_value( $border_color );
$border_color = $border_color !== '' ? $border_color : 'transparent';
$styles[] = 'border:' . $border_width . 'px ' . ( $border_style ?: 'solid' ) . ' ' . $border_color . ';';
$radius_value = $this->resolve_responsive_scalar_style_value( $atts, 'submitRadius', $device, 'number' );
$radius = $radius_value !== null ? floatval( $radius_value ) : 6;
$styles[] = 'border-radius:' . max( 0, $radius ) . 'px;';
$padding_css = $this->resolve_padding_css( $atts, $device );
if ( $padding_css ) {
$styles[] = 'padding:' . $padding_css . ';';
}
$align = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitAlign', $device, 'string' ) );
if ( $align === 'full' ) {
$styles[] = 'width:100%;';
$styles[] = 'display:inline-block;';
$styles[] = 'text-align:center;';
}
$margin_css = $this->resolve_box_css( isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null, $device );
if ( $margin_css ) {
$styles[] = 'margin:' . $margin_css . ';';
}
$typography_styles = $this->build_typography_declarations( isset( $atts['submitTypography'] ) ? $atts['submitTypography'] : null, 'attr', $device );
if ( ! empty( $typography_styles ) ) {
$styles = array_merge( $styles, $typography_styles );
}
return $styles;
}
protected function build_submit_button_responsive_rules( $atts, $device = 'desktop' ) {
$rules = array();
$this->append_resolved_string_rule( $rules, $atts, 'submitBg', 'background', $device, false, false, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitColor', 'color', $device, false, false, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitBorder', 'border-color', $device, false, false, true );
$this->append_resolved_number_rule( $rules, $atts, 'submitBorderWidth', 'border-width', $device, 'px', 0, null, false, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitBorderStyle', 'border-style', $device, false, true, true );
$this->append_resolved_number_rule( $rules, $atts, 'submitRadius', 'border-radius', $device, 'px', 0, null, false, true );
if ( $this->is_responsive_style_value( isset( $atts['submitPadding'] ) ? $atts['submitPadding'] : null ) ) {
$padding_css = $this->resolve_padding_css( $atts, $device );
if ( $padding_css ) {
$this->append_css_rule_if_string( $rules, 'padding', $padding_css );
}
}
if ( $this->is_responsive_style_value( isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null ) ) {
$margin_css = $this->resolve_box_css( isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null, $device );
if ( $margin_css ) {
$this->append_css_rule_if_string( $rules, 'margin', $margin_css );
}
}
if ( $this->is_responsive_style_value( isset( $atts['submitTypography'] ) ? $atts['submitTypography'] : null ) ) {
$rules = array_merge( $rules, $this->build_typography_declarations( isset( $atts['submitTypography'] ) ? $atts['submitTypography'] : null, 'css', $device ) );
}
if ( $this->has_responsive_scalar_style_value( $atts, 'submitAlign', 'string' ) ) {
$align = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitAlign', $device, 'string' ) );
if ( $align === 'full' ) {
$rules[] = 'width:100%;';
} else {
$rules[] = 'width:auto;';
}
$rules[] = 'display:inline-block;';
$rules[] = 'text-align:center;';
}
return $this->append_important_rules( $rules );
}
protected function build_submit_wrap_responsive_rules( $atts, $device = 'desktop' ) {
if (
! $this->is_responsive_style_value( isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null ) &&
! $this->has_responsive_scalar_style_value( $atts, 'submitAlign', 'string' )
) {
return array();
}
$styles = $this->build_wrap_style(
$this->resolve_responsive_scalar_style_value( $atts, 'submitAlign', $device, 'string' ),
isset( $atts['submitMargin'] ) ? $atts['submitMargin'] : null,
$device,
true
);
return $this->append_important_rules( $styles );
}
protected function build_hover_rules( $atts, $device = 'desktop' ) {
$rules = array();
$this->append_resolved_string_rule( $rules, $atts, 'submitHoverBg', 'background', $device, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitHoverColor', 'color', $device, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitHoverBorder', 'border-color', $device, true );
$this->append_resolved_number_rule( $rules, $atts, 'submitHoverBorderWidth', 'border-width', $device, 'px', 0, null, true );
$this->append_resolved_string_rule( $rules, $atts, 'submitHoverBorderStyle', 'border-style', $device, true, true );
$this->append_resolved_number_rule( $rules, $atts, 'submitHoverOpacity', 'opacity', $device, '', 0, 1, true );
return $rules;
}
protected function build_hover_css( $atts, $form_id ) {
$rules = stacklar_sanitize_css_declarations( $this->build_hover_rules( $atts, 'desktop' ) );
if ( empty( $rules ) ) {
return '';
}
$scope = $form_id ? '.stacklar--' . $form_id . ' .stacklar-submit' : '.stacklar-submit';
return $scope . ':hover{' . implode( '', $rules ) . '}';
}
protected function build_focus_rules( $atts, $device = 'desktop' ) {
$color = stacklar_sanitize_css_value( $this->resolve_responsive_scalar_style_value( $atts, 'submitFocusColor', $device, 'string' ) );
if ( $color === '' ) {
return array();
}
$width_value = $this->resolve_responsive_scalar_style_value( $atts, 'submitFocusWidth', $device, 'number' );
$width = $width_value !== null ? max( 0, min( 8, floatval( $width_value ) ) ) : 2;
return array( 'outline:' . $width . 'px solid ' . $color . ' !important;', 'outline-offset:2px;' );
}
protected function build_focus_css( $atts, $form_id ) {
$rules = stacklar_sanitize_css_declarations( $this->build_focus_rules( $atts, 'desktop' ) );
if ( empty( $rules ) ) {
return '';
}
$scope = $form_id ? '.stacklar--' . $form_id . ' .stacklar-submit' : '.stacklar-submit';
return $scope . ':focus,' . $scope . ':focus-visible{' . implode( '', $rules ) . '}';
}
protected function build_multistep_css( $atts, $form_id ) {
if ( ! $form_id ) {
return '';
}
$bg = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBg', 'desktop', 'string' ) );
$bg = $bg !== '' ? $bg : '#111111';
$color = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitColor', 'desktop', 'string' ) );
$color = $color !== '' ? $color : '#ffffff';
$border = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBorder', 'desktop', 'string' ) );
$border = $border !== '' ? $border : $bg;
$border_width_value = $this->resolve_responsive_scalar_style_value( $atts, 'submitBorderWidth', 'desktop', 'number' );
$border_width = $border_width_value !== null ? max( 0, floatval( $border_width_value ) ) : 1;
$border_style = preg_replace( '/[^a-z-]/i', '', (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitBorderStyle', 'desktop', 'string' ) );
$border_style = $border_style !== '' ? $border_style : 'solid';
$hover_bg = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitHoverBg', 'desktop', 'string' ) );
$hover_bg = $hover_bg !== '' ? $hover_bg : $bg;
$hover_color = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitHoverColor', 'desktop', 'string' ) );
$hover_color = $hover_color !== '' ? $hover_color : $color;
$hover_border = trim( (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitHoverBorder', 'desktop', 'string' ) );
$hover_border = $hover_border !== '' ? $hover_border : $border;
$hover_bw_attr = $this->resolve_responsive_scalar_style_value( $atts, 'submitHoverBorderWidth', 'desktop', 'number' );
$hover_bw = $hover_bw_attr !== null && $hover_bw_attr !== '' ? max( 0, floatval( $hover_bw_attr ) ) : $border_width;
$hover_bs = preg_replace( '/[^a-z-]/i', '', (string) $this->resolve_responsive_scalar_style_value( $atts, 'submitHoverBorderStyle', 'desktop', 'string' ) );
$hover_bs = $hover_bs !== '' ? $hover_bs : $border_style;
return $this->build_selector_rule_block(
'.stacklar--' . $form_id,
array(
'--stacklar-btn-bg:' . $bg . ';',
'--stacklar-btn-color:' . $color . ';',
'--stacklar-btn-border:' . $border . ';',
'--stacklar-btn-border-width:' . $border_width . 'px;',
'--stacklar-btn-border-style:' . ( $border_style ?: 'solid' ) . ';',
'--stacklar-btn-bg-hover:' . $hover_bg . ';',
'--stacklar-btn-color-hover:' . $hover_color . ';',
'--stacklar-btn-border-hover:' . $hover_border . ';',
'--stacklar-btn-border-width-hover:' . $hover_bw . 'px;',
'--stacklar-btn-border-style-hover:' . ( $hover_bs ?: $border_style ?: 'solid' ) . ';',
)
);
}
protected function build_message_css( $atts, $form_id ) {
if ( ! $form_id ) {
return '';
}
$scope = '.stacklar--' . $form_id . ' .stacklar-message';
$css = '';
$success = stacklar_sanitize_css_declarations( $this->build_message_rules( $atts, 'success' ) );
if ( ! empty( $success ) ) {
$css .= $scope . '.is-success{' . implode( '', $success ) . '}';
}
$error = stacklar_sanitize_css_declarations( $this->build_message_rules( $atts, 'error' ) );
if ( ! empty( $error ) ) {
$css .= $scope . '.is-error{' . implode( '', $error ) . '}';
}
return $css;
}
protected function form_has_step_blocks( $post_id ) {
static $cache = array();
$post_id = absint( $post_id );
if ( ! $post_id ) {
return false;
}
if ( array_key_exists( $post_id, $cache ) ) {
return (bool) $cache[ $post_id ];
}
$post = get_post( $post_id );
if ( ! $post || ! is_string( $post->post_content ) || '' === $post->post_content ) {
$cache[ $post_id ] = false;
return false;
}
if ( false === strpos( $post->post_content, 'stacklar/form-step' ) ) {
$cache[ $post_id ] = false;
return false;
}
$blocks = parse_blocks( $post->post_content );
$cache[ $post_id ] = $this->blocks_contain_step_block( $blocks );
return (bool) $cache[ $post_id ];
}
protected function blocks_contain_step_block( $blocks ) {
if ( empty( $blocks ) || ! is_array( $blocks ) ) {
return false;
}
foreach ( $blocks as $block ) {
if ( empty( $block ) || ! is_array( $block ) ) {
continue;
}
if ( ! empty( $block['blockName'] ) && 'stacklar/form-step' === $block['blockName'] ) {
return true;
}
if ( ! empty( $block['innerBlocks'] ) && $this->blocks_contain_step_block( $block['innerBlocks'] ) ) {
return true;
}
}
return false;
}
protected function build_message_rules( $atts, $type = 'success', $device = 'desktop' ) {
$prefix = $type === 'error' ? 'messageError' : 'messageSuccess';
$rules = array();
$padding_key = $prefix . 'Padding';
$typo_key = $prefix . 'Typography';
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'Bg', 'background', $device );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'Color', 'color', $device );
$this->append_resolved_number_rule( $rules, $atts, $prefix . 'BorderWidth', 'border-width', $device );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'BorderStyle', 'border-style', $device, false, true );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'BorderColor', 'border-color', $device );
$this->append_resolved_number_rule( $rules, $atts, $prefix . 'BorderRadius', 'border-radius', $device );
if ( ! empty( $atts[ $padding_key ] ) && is_array( $atts[ $padding_key ] ) ) {
$padding = $this->resolve_box_css( $atts[ $padding_key ], $device );
if ( $padding !== '' ) {
$this->append_css_rule_if_string( $rules, 'padding', $padding );
}
}
if ( ! empty( $atts[ $typo_key ] ) ) {
$rules = array_merge( $rules, $this->build_typography_declarations( $atts[ $typo_key ], 'css', $device ) );
}
return $rules;
}
protected function build_message_responsive_rules( $atts, $type = 'success', $device = 'desktop' ) {
$prefix = $type === 'error' ? 'messageError' : 'messageSuccess';
$rules = array();
$padding_key = $prefix . 'Padding';
$typo_key = $prefix . 'Typography';
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'Bg', 'background', $device, false, false, true );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'Color', 'color', $device, false, false, true );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'BorderColor', 'border-color', $device, false, false, true );
$this->append_resolved_number_rule( $rules, $atts, $prefix . 'BorderWidth', 'border-width', $device, 'px', 0, null, false, true );
$this->append_resolved_string_rule( $rules, $atts, $prefix . 'BorderStyle', 'border-style', $device, false, true, true );
$this->append_resolved_number_rule( $rules, $atts, $prefix . 'BorderRadius', 'border-radius', $device, 'px', 0, null, false, true );
if ( $this->is_responsive_style_value( isset( $atts[ $padding_key ] ) ? $atts[ $padding_key ] : null ) ) {
$padding = $this->resolve_box_css( isset( $atts[ $padding_key ] ) ? $atts[ $padding_key ] : null, $device );
if ( $padding !== '' ) {
$this->append_css_rule_if_string( $rules, 'padding', $padding );
}
}
if ( $this->is_responsive_style_value( isset( $atts[ $typo_key ] ) ? $atts[ $typo_key ] : null ) ) {
$rules = array_merge( $rules, $this->build_typography_declarations( isset( $atts[ $typo_key ] ) ? $atts[ $typo_key ] : null, 'css', $device ) );
}
return $this->append_important_rules( $rules );
}
protected function build_submit_responsive_css( $atts, $instance_selector ) {
$instance_selector = trim( (string) $instance_selector );
if ( '' === $instance_selector ) {
return '';
}
$css = '';
$button_selector = $instance_selector . ' .stacklar-submit';
$button_css = $this->build_responsive_selector_css(
$button_selector,
array(
'tablet' => $this->build_submit_button_responsive_rules( $atts, 'tablet' ),
'mobile' => $this->build_submit_button_responsive_rules( $atts, 'mobile' ),
)
);
if ( $button_css ) {
$css .= $button_css;
}
$wrap_selector = $instance_selector . ' .stacklar-submit-wrap';
$wrap_css = $this->build_responsive_selector_css(
$wrap_selector,
array(
'tablet' => $this->build_submit_wrap_responsive_rules( $atts, 'tablet' ),
'mobile' => $this->build_submit_wrap_responsive_rules( $atts, 'mobile' ),
)
);
if ( $wrap_css ) {
$css .= $wrap_css;
}
$has_responsive_hover = $this->has_responsive_scalar_style_value( $atts, 'submitHoverBg', 'string' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitHoverColor', 'string' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitHoverBorder', 'string' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitHoverBorderWidth', 'number' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitHoverBorderStyle', 'string' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitHoverOpacity', 'number' );
if ( $has_responsive_hover ) {
$hover_css = $this->build_responsive_selector_css(
$button_selector . ':hover',
array(
'tablet' => $this->build_hover_rules( $atts, 'tablet' ),
'mobile' => $this->build_hover_rules( $atts, 'mobile' ),
)
);
if ( $hover_css ) {
$css .= $hover_css;
}
}
$has_responsive_focus = $this->has_responsive_scalar_style_value( $atts, 'submitFocusColor', 'string' )
|| $this->has_responsive_scalar_style_value( $atts, 'submitFocusWidth', 'number' );
if ( $has_responsive_focus ) {
$focus_selector = $button_selector . ':focus, ' . $button_selector . ':focus-visible';
$focus_css = $this->build_responsive_selector_css(
$focus_selector,
array(
'tablet' => $this->build_focus_rules( $atts, 'tablet' ),
'mobile' => $this->build_focus_rules( $atts, 'mobile' ),
)
);
if ( $focus_css ) {
$css .= $focus_css;
}
}
$success_selector = $instance_selector . ' .stacklar-message.is-success';
$success_css = $this->build_responsive_selector_css(
$success_selector,
array(
'tablet' => $this->build_message_responsive_rules( $atts, 'success', 'tablet' ),
'mobile' => $this->build_message_responsive_rules( $atts, 'success', 'mobile' ),
)
);
if ( $success_css ) {
$css .= $success_css;
}
$error_selector = $instance_selector . ' .stacklar-message.is-error';
$error_css = $this->build_responsive_selector_css(
$error_selector,
array(
'tablet' => $this->build_message_responsive_rules( $atts, 'error', 'tablet' ),
'mobile' => $this->build_message_responsive_rules( $atts, 'error', 'mobile' ),
)
);
if ( $error_css ) {
$css .= $error_css;
}
return $css;
}
}
}