ÿØÿà JFIF ÿÛ „ ( %"1!%)+...383,7(-.+
-+++--++++---+-+-----+---------------+---+-++7-----ÿÀ ß â" ÿÄ ÿÄ H !1AQaq"‘¡2B±ÁÑð#R“ÒTbr‚²á3csƒ’ÂñDS¢³$CÿÄ ÿÄ % !1AQa"23‘ÿÚ ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6
öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ"Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷ó²·˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%Ìòh´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ÇýÊTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆÑªQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»&
î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$ËÚsäÿ
÷Û #°xŸëí(l »ý3—¥5m!
rt`†0~'j2(]S¦¦kv,ÚÇl¦øJA£ŠƒJ3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡*….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉä¢mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ñ#ºI¤Å´%çÁ‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg
A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±bLô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U Z©RÊÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD
é©¤&‡ïDbàÁôMÁ.ÿØÿà JFIF ÿÛ „ ( %"1!%)+...383,7(-.+
-+++--++++---+-+-----+---------------+---+-++7-----ÿÀ ß â" ÿÄ ÿÄ H !1AQaq"‘¡2B±ÁÑð#R“ÒTbr‚²á3csƒ’ÂñDS¢³$CÿÄ ÿÄ % !1AQa"23‘ÿÚ ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6
öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ"Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷ó²·˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%Ìòh´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ÇýÊTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆÑªQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»&
î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$ËÚsäÿ
÷Û #°xŸëí(l »ý3—¥5m!
rt`†0~'j2(]S¦¦kv,ÚÇl¦øJA£ŠƒJ3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡*….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉä¢mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ñ#ºI¤Å´%çÁ‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg
A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±bLô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U Z©RÊÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD
é©¤&‡ïDbàÁôMÁ.forms = [];
$this->amp_obj = wpforms()->obj( 'amp' );
$this->init_render_engine( wpforms_get_render_engine() );
$this->hooks();
// Register shortcode.
add_shortcode( 'wpforms', [ $this, 'shortcode' ] );
}
/**
* Register hooks.
*
* @since 1.8.1
*/
private function hooks() {
// Actions.
add_action( 'init', [ $this, 'init_style_settings' ] );
add_action( 'wpforms_frontend_output_success', [ $this, 'confirmation' ], 10, 3 );
add_action( 'wpforms_frontend_output', [ $this, 'head' ], 5, 5 );
add_action( 'wpforms_frontend_output', [ $this, 'fields' ], 10, 5 );
add_action( 'wpforms_display_field_before', [ $this, 'field_container_open' ], 5, 2 );
add_action( 'wpforms_display_field_before', [ $this, 'field_fieldset_open' ], 10, 2 );
add_action( 'wpforms_display_field_before', [ $this, 'field_label' ], 15, 2 );
add_action( 'wpforms_display_field_before', [ $this, 'field_description' ], 20, 2 );
add_action( 'wpforms_display_field_after', [ $this, 'field_error' ], 3, 2 );
add_action( 'wpforms_display_field_after', [ $this, 'field_description' ], 5, 2 );
add_action( 'wpforms_display_field_after', [ $this, 'field_fieldset_close' ], 10, 2 );
add_action( 'wpforms_display_field_after', [ $this, 'field_container_close' ], 15, 2 );
add_action( 'wpforms_frontend_output', [ $this, 'foot' ], 25, 5 );
add_action( 'wp_enqueue_scripts', [ $this, 'assets_header' ] );
add_action( 'wp_footer', [ $this, 'assets_footer' ], 15 );
add_action( 'wp_footer', [ $this, 'missing_assets_error_js' ], 20 );
add_action( 'wp_footer', [ $this, 'footer_end' ], 99 );
}
/**
* Initialize render engine.
*
* @since 1.8.1
*
* @param string $engine Render engine slug, `classic` or `modern`.
*/
public function init_render_engine( $engine ) {
$this->render_engine = $engine;
$this->render_obj = wpforms()->obj( "frontend_{$this->render_engine}" );
$this->render_obj->hooks();
}
/**
* Initialize form styling settings.
*
* @since 1.8.1
*/
public function init_style_settings() {
// Skip if modern markup settings is already set.
$modern_markup_is_set = wpforms_setting( 'modern-markup-is-set' );
if ( $modern_markup_is_set ) {
return;
}
$settings = (array) get_option( 'wpforms_settings', [] );
$count_posts = wp_count_posts( 'wpforms' );
// Set the Modern markup checkbox to the checked state for all new users.
$settings['modern-markup'] = ( $count_posts->publish + $count_posts->trash ) === 0 ? '1' : '0';
$settings['modern-markup-is-set'] = true;
// Hide the Modern markup checkbox for all new users.
if ( $settings['modern-markup'] ) {
$settings['modern-markup-hide-setting'] = true;
}
update_option( 'wpforms_settings', $settings );
}
/**
* Primary function to render a form on the frontend.
*
* @since 1.8.1
*
* @param int $id Form ID.
* @param bool $title Whether to display form title.
* @param bool $description Whether to display form description.
*/
public function output( $id, $title = false, $description = false ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
if ( empty( $id ) ) {
return;
}
// Grab the form data, if not found, then we bail.
$form = $this->get_form( $id );
if ( $form === null || empty( $form->post_content ) ) {
return;
}
// We should display only the published form.
if ( ! empty( $form->post_status ) && $form->post_status !== 'publish' ) {
return;
}
// Decode the form data.
$form_data = wpforms_decode( $form->post_content );
// Skip if the form data is empty.
if ( empty( $form_data ) ) {
return;
}
// Basic information.
/**
* Filter frontend form data.
*
* @since 1.4.3
*
* @param array $form_data Form data.
*/
$form_data = (array) apply_filters( 'wpforms_frontend_form_data', $form_data );
$form_id = absint( $form->ID );
$this->action = esc_url_raw( remove_query_arg( 'wpforms' ) );
$errors = empty( wpforms()->obj( 'process' )->errors[ $form_id ] ) ? [] : wpforms()->obj( 'process' )->errors[ $form_id ];
$title = filter_var( $title, FILTER_VALIDATE_BOOLEAN );
$description = filter_var( $description, FILTER_VALIDATE_BOOLEAN );
// Pass the current form data to the render object.
$this->render_obj->form_data = $form_data;
if ( $this->stop_output( $form, $form_data ) ) {
return;
}
// All checks have passed, so calculate multi-page details for the form.
$this->pages = $this->get_pages( $form_data );
/**
* Allow modifying a form action attribute.
*
* @since 1.1.2
*
* @param string $action Action attribute.
* @param array $form_data Form data and settings.
* @param null $deprecated A deprecated argument.
*/
$this->action = apply_filters( 'wpforms_frontend_form_action', $this->action, $form_data, null );
$form_classes = [ 'wpforms-validate', 'wpforms-form' ];
if ( ! empty( $form_data['settings']['ajax_submit'] ) && ! $this->amp_obj->is_amp() ) {
$form_classes[] = 'wpforms-ajax-form';
}
$form_atts = [
'id' => sprintf( 'wpforms-form-%d', absint( $form_id ) ),
'class' => $form_classes,
'data' => [
'formid' => absint( $form_id ),
],
'atts' => [
'method' => 'post',
'enctype' => 'multipart/form-data',
'action' => esc_url( $this->action ),
],
];
/**
* Allow modifying form attributes.
*
* @since 1.4.5
*
* @param array $form_atts Form attributes.
* @param array $form_data Form data and settings.
*/
$form_atts = apply_filters( 'wpforms_frontend_form_atts', $form_atts, $form_data );
$this->form_container_open( $form_data, $form );
/**
* Fires before form output.
*
* @since 1.5.4.2
*
* @param array $form_data Form data.
* @param WP_Post $form Form.
*/
do_action( 'wpforms_frontend_output_form_before', $form_data, $form );
echo '
';
/**
* Allow adding content after a form.
*
* @since 1.5.4.2
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
do_action( 'wpforms_frontend_output_form_after', $form_data, $form );
$this->form_container_close( $form_data, $form );
// Add form to class property that tracks all forms in a page.
$this->forms[ $form_id ] = $form_data;
// Optional debug information if WPFORMS_DEBUG is defined.
wpforms_debug_data( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
/**
* Fires after frontend output.
*
* @since 1.0.0
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
do_action( 'wpforms_frontend_output_after', $form_data, $form );
}
/**
* Get form.
*
* @since 1.8.1
*
* @param int $id Form id.
*
* @return array|WP_Post|null
* @noinspection NullPointerExceptionInspection
*/
private function get_form( $id ) {
if ( empty( $id ) ) {
return null;
}
// Grab the form data, if not found, then we bail.
$form = wpforms()->obj( 'form' )->get( (int) $id );
if ( empty( $form ) ) {
return null;
}
// We should display only the published form.
if ( ! empty( $form->post_status ) && $form->post_status !== 'publish' ) {
return null;
}
return $form;
}
/**
* Check whether we should stop the output.
*
* @since 1.8.1
*
* @param WP_Post $form Form.
* @param array $form_data Form data.
*
* @return bool
*/
private function stop_output( $form, $form_data ): bool {
$form_id = absint( $form->ID );
/**
* Is the form empty?
* Check before output the form on the frontend.
*
* @since 1.7.7
*
* @param bool $form_is_empty Is the form empty?
* @param array $form_data Form data.
*/
$form_is_empty = apply_filters( 'wpforms_frontend_output_form_is_empty', empty( $form_data['fields'] ), $form_data );
// If the form does not contain any fields - do not proceed.
if ( $form_is_empty ) {
$this->render_obj->form_is_empty();
return true;
}
// We need to stop output processing in case we are on AMP page.
if ( $this->amp_obj->stop_output( $form_data ) ) {
return true;
}
// Add url query var wpforms_form_id to track post_max_size overflows.
if ( in_array( 'file-upload', wp_list_pluck( $form_data['fields'], 'type' ), true ) ) {
$this->action = add_query_arg( 'wpforms_form_id', $form_id, $this->action );
}
/**
* Fires before form data output.
*
* @since 1.0.0
*
* @param array $form_data Form data.
* @param WP_Post $form Form.
*/
do_action( 'wpforms_frontend_output_before', $form_data, $form );
if ( $this->output_success( $form ) ) {
return true;
}
/**
* Allow filter to return early if some condition is not met.
*
* @since 1.0.0
*
* @param bool $load Load frontend flag.
* @param array $form_data Form data.
* @param null $deprecated Deprecated.
*/
if ( ! apply_filters( 'wpforms_frontend_load', true, $form_data, null ) ) {
$this->form_container_open( $form_data, $form );
/**
* Fires when frontend is not loaded.
*
* @since 1.4.8
*
* @param array $form_data Form data.
* @param WP_Post $form Form.
*/
do_action( 'wpforms_frontend_not_loaded', $form_data, $form );
$this->form_container_close( $form_data, $form );
return true;
}
return false;
}
/**
* Get pages.
*
* @since 1.8.1
*
* @param array $form_data Form data.
*
* @return array|false
* @noinspection PhpTernaryExpressionCanBeReducedToShortVersionInspection
* @noinspection ElvisOperatorCanBeUsedInspection
*/
private function get_pages( $form_data ) {
$pages = wpforms_get_pagebreak_details( $form_data );
return $pages ? $pages : false;
}
/**
* Check whether output was successful.
*
* @since 1.8.1
*
* @param WP_Post $form Form.
*
* @return bool
*/
private function output_success( $form ): bool {
$form_id = absint( $form->ID );
$process = wpforms()->obj( 'process' );
if ( ! $process ) {
return false;
}
$form_data = $process->form_data;
$errors = empty( $process->errors[ $form_id ] ) ? [] : $process->errors[ $form_id ];
// Check for return hash.
if (
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
! empty( $_GET['wpforms_return'] ) &&
$process->valid_hash &&
(int) $form_data['id'] === $form_id
) {
$this->form_container_open( $form_data, $form );
/**
* Fires at successful output.
*
* @since 1.4.5
*
* @param array $form_data Form data.
* @param array $fields Form fields.
* @param int $entry_id Form ID.
*/
do_action( 'wpforms_frontend_output_success', $form_data, $process->fields, $process->entry_id );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
wpforms_debug_data( $_POST );
$this->form_container_close( $form_data, $form );
return true;
}
// Check for error-free completed form.
if (
// phpcs:disable WordPress.Security.NonceVerification.Missing
empty( $errors ) &&
! empty( $form_data ) &&
! empty( $_POST['wpforms']['id'] ) &&
(int) $_POST['wpforms']['id'] === $form_id
// phpcs:enable WordPress.Security.NonceVerification.Missing
) {
// There is no need for a container wrapper when a form is submitted through AJAX.
$this->form_container_open( $form_data, $form );
/** This action is documented in the same method, several lines above. */
do_action( 'wpforms_frontend_output_success', $form_data, $process->fields, $process->entry_id );
$this->form_container_close( $form_data, $form );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
wpforms_debug_data( $_POST );
return true;
}
return false;
}
/**
* Display form confirmation message.
*
* @since 1.8.1
*
* @param array $form_data Form data and settings.
* @param array $fields Sanitized field data.
* @param int $entry_id Entry id.
*/
public function confirmation( $form_data, $fields = [], $entry_id = 0 ) {
// In AMP, just print template.
if ( $this->amp_obj->output_success_template( $form_data ) ) {
return;
}
list( $fields, $entry_id ) = $this->prepare_confirmation_args( $fields, $entry_id );
$process = wpforms()->obj( 'process' );
$confirmation = $process->get_current_confirmation();
$confirmation_message = $process->get_confirmation_message( $form_data, $fields, $entry_id );
// Only display if a confirmation message has been configured.
if ( empty( $confirmation ) || empty( $confirmation_message ) ) {
return;
}
// Load confirmation-specific assets.
$this->assets_confirmation( $form_data );
/**
* Fires once before the confirmation message.
*
* @since 1.6.9
*
* @param array $confirmation Current confirmation data.
* @param array $form_data Form data and settings.
* @param array $fields Sanitized field data.
* @param int $entry_id Entry id.
*/
do_action( 'wpforms_frontend_confirmation_message_before', $confirmation, $form_data, $fields, $entry_id );
$class = (int) wpforms_setting( 'disable-css', '1' ) === 1 ?
'wpforms-confirmation-container-full' :
'wpforms-confirmation-container';
$class .= $this->confirmation_message_scroll ? ' wpforms-confirmation-scroll' : '';
$this->render_obj->confirmation( $confirmation_message, $class, $form_data );
/**
* Fires once after the confirmation message.
*
* @since 1.6.9
*
* @param array $confirmation Current confirmation data.
* @param array $form_data Form data and settings.
* @param array $fields Sanitized field data.
* @param int $entry_id Entry id.
*/
do_action( 'wpforms_frontend_confirmation_message_after', $confirmation, $form_data, $fields, $entry_id );
}
/**
* Prepare confirmation arguments.
*
* @since 1.8.1
*
* @param array $fields Sanitized field data.
* @param int $entry_id Entry id.
*
* @return array
*/
private function prepare_confirmation_args( $fields = [], $entry_id = 0 ): array {
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
if ( empty( $fields ) ) {
$fields = ! empty( $_POST['wpforms']['complete'] ) ? $_POST['wpforms']['complete'] : [];
}
if ( empty( $entry_id ) ) {
$entry_id = ! empty( $_POST['wpforms']['entry_id'] ) ? $_POST['wpforms']['entry_id'] : 0;
}
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
return [ $fields, $entry_id ];
}
/**
* Form container classes.
*
* @since 1.7.9
*
* @param array $form_data Form data and settings.
*
* @return array
*/
private function get_container_classes( $form_data ): array {
$classes = (int) wpforms_setting( 'disable-css', '1' ) === 1 ? [ 'wpforms-container-full' ] : [];
/**
* Allow form container classes to be filtered and user defined classes.
*
* @since 1.0.0
*
* @param array $classes Classes.
* @param array $form_data Form data and settings.
*/
$classes = (array) apply_filters( 'wpforms_frontend_container_class', $classes, $form_data );
if ( ! empty( $form_data['settings']['form_class'] ) ) {
$classes = array_merge( $classes, explode( ' ', $form_data['settings']['form_class'] ) );
}
return $classes;
}
/**
* Display the opening container markup for a form.
*
* @since 1.7.9
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
private function form_container_open( $form_data, $form ) {
/**
* Fires before container open tag.
*
* @since 1.5.4.2
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
do_action( 'wpforms_frontend_output_container_before', $form_data, $form );
$classes = $this->get_container_classes( $form_data );
$this->render_obj->form_container_open( $classes, $form_data );
}
/**
* Display the closing container markup for a form.
*
* @since 1.7.9
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
private function form_container_close( $form_data, $form ) {
$this->render_obj->form_container_close();
/**
* Fires after container close tag.
*
* @since 1.5.4.2
*
* @param array $form_data Form data and settings.
* @param WP_Post $form Form post type.
*/
do_action( 'wpforms_frontend_output_container_after', $form_data, $form );
}
/**
* Form head area, for displaying form title and description if enabled.
*
* @since 1.8.1
*
* @param array $form_data Form data and settings.
* @param null $deprecated Deprecated in v1.3.7, previously was $form object.
* @param bool $title Whether to display form title.
* @param bool $description Whether to display form description.
* @param array $errors List of all errors filled in WPForms_Process::process().
*
* @noinspection PhpUnusedParameterInspection
*/
public function head( $form_data, $deprecated, $title, $description, $errors ) {
// Output title and/or description.
if ( $title === true || $description === true ) {
$this->render_obj->form_head_container( $title, $description, $form_data );
}
/**
* Filters