ÿØÿà 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ĤÚ;H2RÚ†õ\Ö·Ÿn'¾ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"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ĤÚ;H2RÚ†õ\Ö·Ÿn'¾ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"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 '
'; /** * Fires before closing the form. * * @since 1.0.0 * * @param array $form_data Form data. * @param null $deprecated Null. * @param bool $title Whether to display form title. * @param bool $description Whether to display form description. * @param array $errors Form processing errors. */ do_action( 'wpforms_frontend_output', $form_data, null, $title, $description, $errors ); 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