__( 'Forms', 'tiboform' ), 'public' => false, 'show_ui' => false, 'supports' => array( 'title' ) ) ); register_post_type( 'tiboform_entry', array( 'label' => __( 'Submissions', 'tiboform' ), 'public' => false, 'show_ui' => false, 'supports' => array( 'title' ) ) ); } add_action( 'init', 'tiboform_register_types' ); /** * Pro etkin mi? (Pro eklentisi lisans geçerliyse filtreyi true yapar.) * * @return bool */ function tiboform_is_pro() { return (bool) apply_filters( 'tiboform_is_pro', false ); } /** * Alan türleri. * * @return array */ function tiboform_types() { return apply_filters( 'tiboform_field_types', array( 'text' => __( 'Text', 'tiboform' ), 'email' => __( 'Email', 'tiboform' ), 'tel' => __( 'Phone', 'tiboform' ), 'textarea' => __( 'Long text', 'tiboform' ), 'url' => __( 'Website (URL)', 'tiboform' ), 'number' => __( 'Number', 'tiboform' ), 'select' => __( 'Dropdown', 'tiboform' ), 'radio' => __( 'Single choice', 'tiboform' ), 'checkbox' => __( 'Multiple choice', 'tiboform' ), 'consent' => __( 'Checkbox (single)', 'tiboform' ), 'date' => __( 'Date', 'tiboform' ), 'datetime' => __( 'Date and time', 'tiboform' ), 'hidden' => __( 'Hidden field', 'tiboform' ), 'heading' => __( 'Heading / text', 'tiboform' ), 'page' => __( 'Section / page break', 'tiboform' ), 'kvkk' => __( 'Privacy consent (KVKK)', 'tiboform' ), ) ); } /** * Değer taşımayan (yalnız görsel) alan türleri. * * @return array */ function tiboform_layout_types() { return array( 'heading', 'page' ); } /** * Alan kısaltıcı. * * @param string $id Kimlik. * @param string $type Tür. * @param string $label Etiket. * @param int $required Zorunlu. * @param string $width full|half. * @param array $extra Ek anahtarlar. * @return array */ function tiboform_f( $id, $type, $label, $required = 0, $width = 'full', $extra = array() ) { return array_merge( array( 'id' => $id, 'type' => $type, 'label' => $label, 'required' => $required, 'width' => $width ), $extra ); } /** * Hazır form şablonları. * * @return array anahtar => [ title, desc, fields ] */ function tiboform_templates() { $kvkk = tiboform_f( 'kvkk', 'kvkk', __( 'I have read the privacy notice.', 'tiboform' ), 1 ); $t = array( 'contact' => array( 'title' => __( 'Contact form', 'tiboform' ), 'desc' => __( 'Name, phone, email, subject and message.', 'tiboform' ), 'fields' => array( tiboform_f( 'ad', 'text', __( 'Full name', 'tiboform' ), 1, 'half' ), tiboform_f( 'telefon', 'tel', __( 'Phone', 'tiboform' ), 1, 'half' ), tiboform_f( 'eposta', 'email', __( 'Email', 'tiboform' ), 1 ), tiboform_f( 'konu', 'select', __( 'Subject', 'tiboform' ), 0, 'full', array( 'options' => array( __( 'Information', 'tiboform' ), __( 'Quote request', 'tiboform' ), __( 'Other', 'tiboform' ) ) ) ), tiboform_f( 'mesaj', 'textarea', __( 'Message', 'tiboform' ), 1 ), $kvkk, ), ), 'quote' => array( 'title' => __( 'Quote request', 'tiboform' ), 'desc' => __( 'Company, service, budget and project details.', 'tiboform' ), 'fields' => array( tiboform_f( 'ad', 'text', __( 'Full name', 'tiboform' ), 1, 'half' ), tiboform_f( 'firma', 'text', __( 'Company', 'tiboform' ), 0, 'half' ), tiboform_f( 'eposta', 'email', __( 'Email', 'tiboform' ), 1, 'half' ), tiboform_f( 'telefon', 'tel', __( 'Phone', 'tiboform' ), 1, 'half' ), tiboform_f( 'hizmet', 'select', __( 'Service', 'tiboform' ), 1, 'half', array( 'options' => array( __( 'Service A', 'tiboform' ), __( 'Service B', 'tiboform' ), __( 'Other', 'tiboform' ) ) ) ), tiboform_f( 'butce', 'select', __( 'Budget', 'tiboform' ), 0, 'half', array( 'options' => array( __( 'Under 10,000 TL', 'tiboform' ), __( '10,000–50,000 TL', 'tiboform' ), __( 'Over 50,000 TL', 'tiboform' ) ) ) ), tiboform_f( 'tarih', 'date', __( 'Preferred start date', 'tiboform' ), 0, 'half' ), tiboform_f( 'web', 'url', __( 'Website', 'tiboform' ), 0, 'half' ), tiboform_f( 'detay', 'textarea', __( 'Project details', 'tiboform' ), 1 ), $kvkk, ), ), 'appointment' => array( 'title' => __( 'Appointment request', 'tiboform' ), 'desc' => __( 'Preferred date and time with contact details.', 'tiboform' ), 'fields' => array( tiboform_f( 'ad', 'text', __( 'Full name', 'tiboform' ), 1, 'half' ), tiboform_f( 'telefon', 'tel', __( 'Phone', 'tiboform' ), 1, 'half' ), tiboform_f( 'eposta', 'email', __( 'Email', 'tiboform' ), 0 ), tiboform_f( 'hizmet', 'select', __( 'Service', 'tiboform' ), 1, 'full', array( 'options' => array( __( 'Consultation', 'tiboform' ), __( 'Check-up', 'tiboform' ), __( 'Other', 'tiboform' ) ) ) ), tiboform_f( 'zaman', 'datetime', __( 'Preferred date and time', 'tiboform' ), 1, 'half' ), tiboform_f( 'alternatif', 'radio', __( 'Best time to call you', 'tiboform' ), 0, 'half', array( 'options' => array( __( 'Morning', 'tiboform' ), __( 'Afternoon', 'tiboform' ), __( 'Evening', 'tiboform' ) ) ) ), tiboform_f( 'not', 'textarea', __( 'Note', 'tiboform' ), 0 ), $kvkk, ), ), 'job' => array( 'title' => __( 'Job application', 'tiboform' ), 'desc' => __( 'Position, experience and a short cover letter (no file).', 'tiboform' ), 'fields' => array( tiboform_f( 'ad', 'text', __( 'Full name', 'tiboform' ), 1, 'half' ), tiboform_f( 'telefon', 'tel', __( 'Phone', 'tiboform' ), 1, 'half' ), tiboform_f( 'eposta', 'email', __( 'Email', 'tiboform' ), 1, 'half' ), tiboform_f( 'dogum', 'date', __( 'Date of birth', 'tiboform' ), 0, 'half' ), tiboform_f( 'pozisyon', 'select', __( 'Position', 'tiboform' ), 1, 'half', array( 'options' => array( __( 'Sales', 'tiboform' ), __( 'Customer support', 'tiboform' ), __( 'Internship', 'tiboform' ), __( 'Other', 'tiboform' ) ) ) ), tiboform_f( 'deneyim', 'number', __( 'Years of experience', 'tiboform' ), 0, 'half', array( 'min' => '0', 'max' => '50' ) ), tiboform_f( 'linkedin', 'url', __( 'LinkedIn or portfolio link', 'tiboform' ), 0 ), tiboform_f( 'onyazi', 'textarea', __( 'Tell us about yourself', 'tiboform' ), 1 ), $kvkk, ), ), 'feedback' => array( 'title' => __( 'Feedback / survey', 'tiboform' ), 'desc' => __( 'Satisfaction score, choices and comments.', 'tiboform' ), 'fields' => array( tiboform_f( 'puan', 'radio', __( 'How satisfied are you?', 'tiboform' ), 1, 'full', array( 'options' => array( '1', '2', '3', '4', '5' ) ) ), tiboform_f( 'begendiniz', 'checkbox', __( 'What did you like?', 'tiboform' ), 0, 'full', array( 'options' => array( __( 'Quality', 'tiboform' ), __( 'Price', 'tiboform' ), __( 'Speed', 'tiboform' ), __( 'Staff', 'tiboform' ) ) ) ), tiboform_f( 'tavsiye', 'select', __( 'Would you recommend us?', 'tiboform' ), 0, 'full', array( 'options' => array( __( 'Yes', 'tiboform' ), __( 'Maybe', 'tiboform' ), __( 'No', 'tiboform' ) ) ) ), tiboform_f( 'yorum', 'textarea', __( 'Comments', 'tiboform' ), 0 ), tiboform_f( 'eposta', 'email', __( 'Email (optional)', 'tiboform' ), 0 ), ), ), 'newsletter' => array( 'title' => __( 'Newsletter signup', 'tiboform' ), 'desc' => __( 'Name, email and permission to send messages.', 'tiboform' ), 'fields' => array( tiboform_f( 'ad', 'text', __( 'Name', 'tiboform' ), 0, 'half' ), tiboform_f( 'eposta', 'email', __( 'Email', 'tiboform' ), 1, 'half' ), tiboform_f( 'izin', 'consent', __( 'I agree to receive email newsletters.', 'tiboform' ), 1 ), $kvkk, ), ), ); return apply_filters( 'tiboform_templates', $t ); } /** * Örnek form (iletişim şablonu). * * @param string $template Şablon anahtarı. * @return array */ function tiboform_sample_form( $template = 'contact' ) { $t = tiboform_templates(); $t = isset( $t[ $template ] ) ? $t[ $template ] : $t['contact']; return array( 'fields' => $t['fields'], 'settings' => tiboform_default_settings(), ); } /** * Şablondan form oluştur. * * @param string $template Şablon. * @param string $title Başlık (boşsa şablon adı). * @param array $settings Ayar ezmeleri. * @return int Form kimliği (0: hata). */ function tiboform_create_form( $template = 'contact', $title = '', $settings = array() ) { $all = tiboform_templates(); $key = isset( $all[ $template ] ) ? $template : 'contact'; $s = tiboform_sample_form( $key ); $s['settings'] = array_merge( $s['settings'], (array) $settings ); $s = tiboform_clean_schema( $s ); $id = wp_insert_post( array( 'post_type' => 'tiboform_form', 'post_status' => 'publish', 'post_title' => $title ? $title : $all[ $key ]['title'], 'post_content' => wp_slash( wp_json_encode( $s ) ) ) ); return is_wp_error( $id ) ? 0 : (int) $id; } /** * TEMA API'si: tema için kalıcı bir form döndürür; yoksa şablondan oluşturur. * Formun rengi boş bırakılır, böylece temanın vurgu rengi (--tfm-ac) kullanılır. * * Örnek: $id = tiboform_get_or_create_form( 'tiboklinik-iletisim', 'contact', 'İletişim' ); * echo tiboform_render_form( $id ); * * @param string $key Tema anahtarı (ör. "tiboklinik-iletisim"). * @param string $template Şablon: contact, quote, appointment, job, feedback, newsletter. * @param string $title Form başlığı. * @return int Form kimliği (0: oluşturulamadı). */ function tiboform_get_or_create_form( $key, $template = 'contact', $title = '' ) { $key = sanitize_key( $key ); if ( '' === $key ) { return 0; } $map = get_option( 'tiboform_theme_forms', array() ); $map = is_array( $map ) ? $map : array(); if ( ! empty( $map[ $key ] ) && 'tiboform_form' === get_post_type( (int) $map[ $key ] ) && 'trash' !== get_post_status( (int) $map[ $key ] ) ) { return (int) $map[ $key ]; } if ( ! post_type_exists( 'tiboform_form' ) ) { tiboform_register_types(); } $id = tiboform_create_form( $template, $title, array( 'color' => '' ) ); if ( $id ) { $map[ $key ] = $id; update_option( 'tiboform_theme_forms', $map, false ); do_action( 'tiboform_theme_form_created', $id, $key, $template ); } return $id; } /** * Varsayılan form ayarları. * * @return array */ function tiboform_default_settings() { return apply_filters( 'tiboform_default_settings', array( 'to' => get_option( 'admin_email' ), 'subject' => __( 'New form submission: {form_adi}', 'tiboform' ), 'body' => '{tum_alanlar}', 'button' => __( 'Send', 'tiboform' ), 'success' => __( 'Thank you! We received your message and will get back to you soon.', 'tiboform' ), 'redirect' => '', 'reply' => 0, 'reply_subject' => __( 'We received your message', 'tiboform' ), 'reply_body' => __( 'Hello, thank you for contacting us. We will get back to you as soon as possible.', 'tiboform' ), 'kvkk_url' => '', 'keep_days' => 180, 'color' => '', ) ); } /** * Form şeması. * * @param int $id Form. * @return array|null */ function tiboform_form( $id ) { $p = get_post( $id ); if ( ! $p || 'tiboform_form' !== $p->post_type ) { return null; } $s = json_decode( $p->post_content, true ); $s = is_array( $s ) ? $s : array(); return array( 'id' => $p->ID, 'title' => $p->post_title, 'fields' => isset( $s['fields'] ) && is_array( $s['fields'] ) ? $s['fields'] : array(), 'settings' => wp_parse_args( isset( $s['settings'] ) ? (array) $s['settings'] : array(), tiboform_default_settings() ), ); } /** * Dizi içindeki tüm değerleri ve anahtarları temizler (iç içe diziler dahil). * * @param mixed $v Ham değer. * @param bool $html true: güvenli HTML korunur (wp_kses_post), false: düz metin (satır sonları korunur). * @return mixed */ function tiboform_sanitize_deep( $v, $html = false ) { if ( is_array( $v ) ) { $out = array(); foreach ( $v as $k => $x ) { $out[ is_int( $k ) ? $k : sanitize_key( $k ) ] = tiboform_sanitize_deep( $x, $html ); } return $out; } if ( is_bool( $v ) || is_int( $v ) || is_float( $v ) ) { return $v; } if ( ! is_string( $v ) ) { return ''; } return $html ? wp_kses_post( $v ) : sanitize_textarea_field( $v ); } /** * Şemayı temizle (yönetimden gelen JSON). * * @param array $raw Ham şema. * @return array */ function tiboform_clean_schema( $raw ) { $fields = array(); $seen = array(); $known = array( 'id', 'type', 'label', 'required', 'options', 'placeholder', 'width', 'min', 'max', 'value' ); foreach ( isset( $raw['fields'] ) ? (array) $raw['fields'] : array() as $f ) { if ( ! is_array( $f ) ) { continue; } // Bilinmeyen tür (ör. Pro kapalıyken Pro alanı) korunur; çizimde atlanır. $type = sanitize_key( isset( $f['type'] ) ? $f['type'] : '' ); $type = $type ? $type : 'text'; $id = sanitize_key( isset( $f['id'] ) ? $f['id'] : '' ); $id = $id ? $id : $type . '_' . wp_rand( 100, 999 ); while ( isset( $seen[ $id ] ) ) { $id .= '_2'; } $seen[ $id ] = 1; $num = function ( $k ) use ( $f ) { return isset( $f[ $k ] ) && is_numeric( $f[ $k ] ) ? (string) ( 0 + $f[ $k ] ) : ''; }; $clean = array( 'id' => $id, 'type' => $type, 'label' => wp_kses( isset( $f['label'] ) ? (string) $f['label'] : '', array( 'b' => array(), 'strong' => array(), 'em' => array(), 'a' => array( 'href' => array(), 'target' => array() ) ) ), 'required' => empty( $f['required'] ) ? 0 : 1, 'options' => array_values( array_filter( array_map( 'sanitize_text_field', isset( $f['options'] ) ? (array) $f['options'] : array() ), 'strlen' ) ), 'placeholder' => sanitize_text_field( isset( $f['placeholder'] ) ? $f['placeholder'] : '' ), 'width' => isset( $f['width'] ) && 'half' === $f['width'] ? 'half' : 'full', 'min' => $num( 'min' ), 'max' => $num( 'max' ), 'value' => sanitize_text_field( isset( $f['value'] ) ? $f['value'] : '' ), ); // Ek anahtarlar (Pro: koşul, formül, dosya ayarları) kaybolmasın diye düz metin olarak korunur. $n = 0; foreach ( $f as $k => $v ) { $k = sanitize_key( $k ); if ( '' === $k || in_array( $k, $known, true ) || ! is_scalar( $v ) || ++$n > 30 ) { continue; } $clean[ $k ] = tiboform_substr( sanitize_text_field( (string) $v ), 0, 500 ); } $fields[] = apply_filters( 'tiboform_clean_field', $clean, $f ); } $d = tiboform_default_settings(); $s = isset( $raw['settings'] ) ? (array) $raw['settings'] : array(); $g = function ( $k ) use ( $s, $d ) { return isset( $s[ $k ] ) ? $s[ $k ] : ( isset( $d[ $k ] ) ? $d[ $k ] : '' ); }; $col = sanitize_hex_color( (string) $g( 'color' ) ); $out = array( 'to' => implode( ',', array_filter( array_map( 'sanitize_email', explode( ',', (string) $g( 'to' ) ) ) ) ), 'subject' => sanitize_text_field( $g( 'subject' ) ), 'body' => sanitize_textarea_field( $g( 'body' ) ), 'button' => sanitize_text_field( $g( 'button' ) ), 'success' => sanitize_text_field( $g( 'success' ) ), 'redirect' => esc_url_raw( (string) $g( 'redirect' ), array( 'http', 'https' ) ), 'reply' => empty( $s['reply'] ) ? 0 : 1, 'reply_subject' => sanitize_text_field( $g( 'reply_subject' ) ), 'reply_body' => sanitize_textarea_field( $g( 'reply_body' ) ), 'kvkk_url' => esc_url_raw( (string) $g( 'kvkk_url' ) ), 'keep_days' => min( 3650, absint( $g( 'keep_days' ) ) ), 'color' => $col ? $col : '', ); return array( 'fields' => array_slice( $fields, 0, 80 ), 'settings' => apply_filters( 'tiboform_clean_settings', $out, $s ), ); } /** * Gönderim sonrası durum mesajları. * * @param array $form Form. * @return array */ function tiboform_status_messages( $form ) { return apply_filters( 'tiboform_status_messages', array( 'err' => __( 'Please check the highlighted fields and try again.', 'tiboform' ), 'closed' => __( 'This form is not accepting submissions right now.', 'tiboform' ), 'dup' => __( 'You have already submitted this form.', 'tiboform' ), 'spam' => __( 'Your submission could not be verified. Please try again.', 'tiboform' ), ), $form ); } /** * HTML öznitelik dizisini yaz. * * @param array $a Öznitelikler. * @return string */ function tiboform_attrs( $a ) { $h = ''; foreach ( (array) $a as $k => $v ) { if ( null === $v || false === $v ) { continue; } $h .= ' ' . esc_attr( $k ) . ( true === $v ? '' : '="' . esc_attr( (string) $v ) . '"' ); } return $h; } /** * Gizli alan değeri: {get:utm_source} gibi adres çubuğu parametreleri desteklenir. * * @param string $v Ayar. * @return string */ function tiboform_hidden_value( $v ) { return preg_replace_callback( '/\{get:([a-z0-9_\-]+)\}/i', function ( $m ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only prefill of a hidden field on a public, cacheable page (e.g. utm_source); nothing is changed and the value is sanitized. return isset( $_GET[ $m[1] ] ) && is_scalar( $_GET[ $m[1] ] ) ? sanitize_text_field( wp_unslash( $_GET[ $m[1] ] ) ) : ''; }, (string) $v ); } /** * Tek alanın HTML'i. * * @param array $f Alan. * @param string $uid Benzersiz önek. * @param array $form Form. * @return string */ function tiboform_field_html( $f, $uid, $form ) { $s = $form['settings']; $types = tiboform_types(); $name = 'tiboform_f[' . $f['id'] . ']'; $fid = $uid . '-' . $f['id']; $req = ! empty( $f['required'] ) ? ' required' : ''; $star = ! empty( $f['required'] ) ? ' ' : ''; $attrs = apply_filters( 'tiboform_field_attrs', array( 'class' => 'tfm-f tfm-' . $f['type'] . ( 'half' === $f['width'] ? ' is-half' : '' ), 'data-tiboform-id' => $f['id'], ), $f, $form ); $open = ''; $ph = isset( $f['placeholder'] ) ? $f['placeholder'] : ''; $label = esc_html( wp_strip_all_tags( $f['label'] ) ); // Pro ya da başka eklentilerin kendi alan türleri. $custom = apply_filters( 'tiboform_render_field', null, $f, $fid, $form, $open ); if ( null !== $custom ) { return (string) $custom; } if ( ! isset( $types[ $f['type'] ] ) ) { return ''; } switch ( $f['type'] ) { case 'heading': return $open . '

' . wp_kses_post( $f['label'] ) . '

'; case 'page': return $open . '

' . $label . '

'; case 'hidden': return ''; case 'kvkk': $l = $s['kvkk_url'] ? '' . wp_kses( $f['label'], array( 'b' => array() ) ) . '' : wp_kses( $f['label'], array( 'b' => array(), 'a' => array( 'href' => array(), 'target' => array() ) ) ); return $open . ''; case 'consent': return $open . ''; case 'radio': case 'checkbox': $h = $open . '
' . $label . $star . ''; foreach ( $f['options'] as $o ) { $h .= ''; } return $h . '
'; } $h = $open . ''; if ( 'textarea' === $f['type'] ) { $h .= ''; } elseif ( 'select' === $f['type'] ) { $h .= ''; } else { $map = array( 'datetime' => 'datetime-local' ); $auto = array( 'email' => 'email', 'tel' => 'tel', 'url' => 'url' ); $a = array( 'id' => $fid, 'type' => isset( $map[ $f['type'] ] ) ? $map[ $f['type'] ] : $f['type'], 'name' => $name, 'placeholder' => '' !== $ph ? $ph : null, 'autocomplete' => isset( $auto[ $f['type'] ] ) ? $auto[ $f['type'] ] : null, 'required' => ! empty( $f['required'] ), ); if ( 'number' === $f['type'] ) { $a['min'] = '' !== (string) $f['min'] ? $f['min'] : null; $a['max'] = '' !== (string) $f['max'] ? $f['max'] : null; $a['step'] = 'any'; } $h .= ''; } return $h . ''; } /** * Formun HTML'i (tema ve kısa kod için). * * @param int $id Form. * @param array $args { dark: bool, class: string }. * @return string */ function tiboform_render_form( $id, $args = array() ) { $form = tiboform_form( absint( $id ) ); if ( ! $form ) { return ''; } $args = wp_parse_args( $args, array( 'dark' => false, 'class' => '' ) ); wp_enqueue_style( 'tiboform-form', TIBOFORM_URL . 'assets/form.css', array(), TIBOFORM_VERSION ); do_action( 'tiboform_enqueue_form', $form ); $s = $form['settings']; $cls = trim( 'tfm' . ( $args['dark'] ? ' is-dark' : '' ) . ' ' . sanitize_html_class( $args['class'] ) ); $style = $s['color'] ? '--tfm-color:' . $s['color'] : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only: only selects which result message (ok/err) to display after the redirect; nothing is changed. $st = isset( $_GET['tiboform_id'] ) && absint( $_GET['tiboform_id'] ) === $form['id'] ? sanitize_key( wp_unslash( $_GET['tiboform_st'] ?? '' ) ) : ''; if ( 'ok' === $st ) { return '

' . esc_html( $s['success'] ) . '

'; } $closed = apply_filters( 'tiboform_form_closed', '', $form ); if ( '' !== $closed ) { return '

' . esc_html( $closed ) . '

'; } static $n = 0; $uid = 'tiboform-' . $form['id'] . '-' . ( ++$n ); $back = get_permalink() ? get_permalink() : home_url( add_query_arg( array() ) ); $attrs = apply_filters( 'tiboform_form_attrs', array( 'class' => $cls, 'id' => 1 === $n ? 'tiboform-' . $form['id'] : $uid, 'method' => 'post', 'action' => admin_url( 'admin-post.php' ), 'style' => $style, 'data-tiboform-uid' => $uid, ), $form ); $ts = time(); $h = ''; $h .= ''; $h .= ''; if ( '' !== $st ) { $msgs = tiboform_status_messages( $form ); $h .= ''; } $h .= '
'; foreach ( $form['fields'] as $f ) { $h .= tiboform_field_html( wp_parse_args( $f, array( 'required' => 0, 'width' => 'full', 'options' => array(), 'min' => '', 'max' => '', 'value' => '', 'placeholder' => '' ) ), $uid, $form ); } $h .= '
' . apply_filters( 'tiboform_before_button', '', $form ) . '
'; return apply_filters( 'tiboform_form_html', $h, $form ); } /** * Kısa kod: [tiboform id="12"] ya da tema için [tiboform key="iletisim" template="contact" title="İletişim" dark="1"] * * @param array $a Öznitelikler. * @return string */ function tiboform_shortcode( $a ) { $a = shortcode_atts( array( 'id' => 0, 'key' => '', 'template' => 'contact', 'title' => '', 'dark' => '', 'class' => '' ), $a, 'tiboform' ); $id = absint( $a['id'] ); if ( ! $id && $a['key'] ) { $id = tiboform_get_or_create_form( $a['key'], $a['template'], $a['title'] ); } return tiboform_render_form( $id, array( 'dark' => ! empty( $a['dark'] ), 'class' => $a['class'] ) ); } add_shortcode( 'tiboform', 'tiboform_shortcode' ); /** * Bir alanın gönderilen değerini temizle ve doğrula (yerleşik türler). * * @param array $f Alan. * @param mixed $v Ham değer. * @return string|WP_Error */ function tiboform_clean_value( $f, $v ) { switch ( $f['type'] ) { case 'checkbox': return implode( ', ', array_intersect( array_map( 'sanitize_text_field', (array) $v ), $f['options'] ) ); case 'select': case 'radio': return is_scalar( $v ) && in_array( (string) $v, $f['options'], true ) ? (string) $v : ''; case 'textarea': return is_scalar( $v ) ? tiboform_substr( sanitize_textarea_field( (string) $v ), 0, 5000 ) : ''; case 'email': $e = is_scalar( $v ) ? sanitize_email( (string) $v ) : ''; return ( '' !== (string) $v && '' === $e ) ? new WP_Error( 'err' ) : $e; case 'url': $v = is_scalar( $v ) ? trim( (string) $v ) : ''; if ( '' === $v ) { return ''; } $v = preg_match( '#^https?://#i', $v ) ? $v : 'https://' . $v; $u = esc_url_raw( $v, array( 'http', 'https' ) ); return $u && wp_http_validate_url( $u ) ? tiboform_substr( $u, 0, 500 ) : new WP_Error( 'err' ); case 'number': $v = is_scalar( $v ) ? str_replace( ',', '.', trim( (string) $v ) ) : ''; if ( '' === $v ) { return ''; } if ( ! is_numeric( $v ) || ( '' !== (string) $f['min'] && (float) $v < (float) $f['min'] ) || ( '' !== (string) $f['max'] && (float) $v > (float) $f['max'] ) ) { return new WP_Error( 'err' ); } return (string) ( 0 + $v ); case 'date': $v = is_scalar( $v ) ? (string) $v : ''; return preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) ? $v : ''; case 'datetime': $v = is_scalar( $v ) ? (string) $v : ''; return preg_match( '/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/', $v, $m ) ? $m[1] . ' ' . $m[2] : ''; case 'kvkk': return empty( $v ) ? '' : __( 'Accepted', 'tiboform' ) . ' (' . wp_date( 'Y-m-d H:i' ) . ')'; case 'consent': return empty( $v ) ? '' : __( 'Yes', 'tiboform' ); } return is_scalar( $v ) ? tiboform_substr( sanitize_text_field( (string) $v ), 0, 500 ) : ''; } /** * Gönderim. */ function tiboform_submit() { // phpcs:disable WordPress.Security.NonceVerification.Missing -- herkese açık form; zaman damgası imzası, bal küpü ve hız sınırı ile korunur (sayfa önbelleğinde nonce bayatlar). $fid = isset( $_POST['tiboform_form'] ) ? absint( $_POST['tiboform_form'] ) : 0; $back = isset( $_POST['tiboform_back'] ) ? esc_url_raw( wp_unslash( $_POST['tiboform_back'] ) ) : home_url( '/' ); $back = wp_validate_redirect( $back, home_url( '/' ) ); $form = tiboform_form( $fid ); $go = function ( $st ) use ( $back, $fid ) { wp_safe_redirect( add_query_arg( array( 'tiboform_id' => $fid, 'tiboform_st' => $st ), remove_query_arg( array( 'tiboform_id', 'tiboform_st' ), $back ) ) . '#tiboform-' . $fid ); exit; }; if ( ! $form ) { $go( 'err' ); } // Bal küpü ve 3 saniyeden hızlı gönderim: sessizce başarılı gibi davran. $t = isset( $_POST['tiboform_t'] ) ? sanitize_text_field( wp_unslash( $_POST['tiboform_t'] ) ) : ''; list( $ts, $sig ) = array_pad( explode( '.', $t, 2 ), 2, '' ); if ( ! empty( $_POST['tiboform_website'] ) || ! hash_equals( wp_hash( $ts . '|' . $fid ), $sig ) || time() - (int) $ts < 3 ) { $go( 'ok' ); } $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; $rk = 'tiboform_rl_' . md5( $ip ); $hits = (int) get_transient( $rk ); if ( $hits >= (int) apply_filters( 'tiboform_rate_limit', 5 ) ) { $go( 'err' ); } $pre = apply_filters( 'tiboform_pre_submit', null, $form ); if ( is_wp_error( $pre ) ) { $go( sanitize_key( $pre->get_error_code() ) ); } // Ham değerler hiçbir filtreye ulaşmadan temizlenir; ardından alan türüne göre ayrıca doğrulanır. $in = isset( $_POST['tiboform_f'] ) && is_array( $_POST['tiboform_f'] ) ? tiboform_sanitize_deep( wp_unslash( $_POST['tiboform_f'] ) ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- tiboform_sanitize_deep() her değeri temizler. // phpcs:enable $data = array(); $types = tiboform_types(); foreach ( $form['fields'] as $f ) { $f = wp_parse_args( $f, array( 'required' => 0, 'options' => array(), 'min' => '', 'max' => '', 'value' => '', 'label' => '' ) ); if ( in_array( $f['type'], tiboform_layout_types(), true ) || ! isset( $types[ $f['type'] ] ) ) { continue; } // Koşullu mantıkla gizlenen alanlar doğrulanmaz ve kaydedilmez. if ( apply_filters( 'tiboform_skip_field', false, $f, $in, $form ) ) { continue; } $raw = isset( $in[ $f['id'] ] ) ? $in[ $f['id'] ] : ''; $v = apply_filters( 'tiboform_field_value', null, $f, $raw, $form ); if ( null === $v ) { $v = tiboform_clean_value( $f, $raw ); } if ( is_wp_error( $v ) ) { $go( 'err' ); } $row = is_array( $v ) ? $v : array( 'value' => (string) $v ); if ( $f['required'] && '' === (string) $row['value'] ) { $go( 'err' ); } $data[ $f['id'] ] = array_merge( array( 'label' => wp_strip_all_tags( $f['label'] ), 'type' => $f['type'] ), $row ); } $data = apply_filters( 'tiboform_entry_data', $data, $form, $in ); $ok = apply_filters( 'tiboform_validate_entry', true, $data, $form ); if ( is_wp_error( $ok ) ) { $go( sanitize_key( $ok->get_error_code() ) ); } set_transient( $rk, $hits + 1, 10 * MINUTE_IN_SECONDS ); $eid = wp_insert_post( array( 'post_type' => 'tiboform_entry', 'post_status' => 'publish', 'post_parent' => $fid, 'post_title' => $form['title'] . ' — ' . wp_date( 'Y-m-d H:i' ), 'meta_input' => array( '_tiboform_data' => $data, '_tiboform_status' => 'new', '_tiboform_page' => $back ), ) ); if ( ! $eid || is_wp_error( $eid ) ) { $go( 'err' ); } do_action( 'tiboform_entry_saved', $eid, $form, $data ); tiboform_send_mails( $eid, $form, $data ); do_action( 'tiboform_submitted', $eid, $form, $data ); $url = apply_filters( 'tiboform_redirect_url', $form['settings']['redirect'], $form, $eid, $data ); if ( $url ) { // Yönetici tarafından girilen adres (başka alan adı olabilir). wp_redirect( esc_url_raw( $url ) ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect exit; } $go( 'ok' ); } add_action( 'admin_post_tiboform_submit', 'tiboform_submit' ); add_action( 'admin_post_nopriv_tiboform_submit', 'tiboform_submit' ); /** * Değerin HTML gösterimi (e-posta, yönetim). * * @param array $d Satır. * @param int $eid Başvuru. * @param string $ctx mail|admin. * @return string */ function tiboform_value_html( $d, $eid = 0, $ctx = 'mail' ) { return (string) apply_filters( 'tiboform_value_html', nl2br( esc_html( (string) $d['value'] ) ), $d, $eid, $ctx ); } /** * Tüm alanlar tablosu. * * @param array $data Veri. * @param int $eid Başvuru. * @return string */ function tiboform_fields_table( $data, $eid = 0 ) { $rows = ''; foreach ( $data as $d ) { $rows .= '' . esc_html( $d['label'] ) . '' . tiboform_value_html( $d, $eid, 'mail' ) . ''; } return '' . $rows . '
'; } /** * Birleştirme etiketleri: {alan_id}, {form_adi}, {tarih}, {tum_alanlar} (İngilizce eşleri: {form_name}, {date}, {all_fields}). * * @param string $text Metin. * @param array $form Form. * @param array $data Veri. * @param bool $html HTML çıktı. * @param int $eid Başvuru. * @return string */ function tiboform_merge( $text, $form, $data, $html = true, $eid = 0 ) { $date = wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); if ( $html ) { $all = tiboform_fields_table( $data, $eid ); } else { $all = ''; foreach ( $data as $d ) { $all .= $d['label'] . ': ' . $d['value'] . "\n"; } } $map = array( '{form_adi}' => $html ? esc_html( $form['title'] ) : $form['title'], '{form_name}' => $html ? esc_html( $form['title'] ) : $form['title'], '{tarih}' => $html ? esc_html( $date ) : $date, '{date}' => $html ? esc_html( $date ) : $date, '{tum_alanlar}' => $all, '{all_fields}' => $all, '{site}' => $html ? esc_html( get_bloginfo( 'name' ) ) : get_bloginfo( 'name' ), ); foreach ( $data as $id => $d ) { $map[ '{' . $id . '}' ] = $html ? tiboform_value_html( $d, $eid, 'mail' ) : (string) $d['value']; } $map = apply_filters( 'tiboform_merge_tags', $map, $form, $data, $html ); if ( $html ) { // Önce metin kaçışlanır, sonra etiketler (zaten güvenli) yerleştirilir. $text = nl2br( esc_html( (string) $text ) ); $text = str_replace( '{tum_alanlar}
', '{tum_alanlar}', $text ); } return strtr( (string) $text, $map ); } /** * E-postayı HTML kabuğa sar. * * @param string $inner İçerik. * @param array $form Form. * @return string */ function tiboform_mail_wrap( $inner, $form ) { $h = '
' . $inner . '
'; return (string) apply_filters( 'tiboform_mail_html', $h, $inner, $form ); } /** * Bildirim ve otomatik yanıt e-postaları. * * @param int $eid Başvuru. * @param array $form Form. * @param array $data Veri. */ function tiboform_send_mails( $eid, $form, $data ) { $s = $form['settings']; $reply = ''; foreach ( $data as $d ) { if ( isset( $d['type'] ) && 'email' === $d['type'] && is_email( $d['value'] ) ) { $reply = $d['value']; break; } } $body = '' !== trim( (string) $s['body'] ) ? $s['body'] : '{tum_alanlar}'; $inner = '

' . esc_html( $form['title'] ) . '

' . tiboform_merge( $body, $form, $data, true, $eid ) . '

' . esc_html__( 'Open submission', 'tiboform' ) . '

'; $html = tiboform_mail_wrap( $inner, $form ); $hdrs = array( 'Content-Type: text/html; charset=UTF-8' ); if ( $reply ) { $hdrs[] = 'Reply-To: ' . $reply; } $to = array_filter( array_map( 'trim', explode( ',', (string) $s['to'] ) ), 'is_email' ); $to = array_unique( (array) apply_filters( 'tiboform_notify_recipients', $to, $form, $data, $eid ) ); $subj = wp_strip_all_tags( tiboform_merge( $s['subject'], $form, $data, false, $eid ) ); foreach ( $to as $addr ) { wp_mail( $addr, $subj, $html, $hdrs ); } if ( $s['reply'] && $reply ) { $rh = tiboform_mail_wrap( '
' . tiboform_merge( $s['reply_body'], $form, $data, true, $eid ) . '

' . esc_html( get_bloginfo( 'name' ) ) . '

', $form ); wp_mail( $reply, wp_strip_all_tags( tiboform_merge( $s['reply_subject'], $form, $data, false, $eid ) ), $rh, array( 'Content-Type: text/html; charset=UTF-8' ) ); } } /** * Başvuru durumları. * * @return array */ function tiboform_statuses() { return array( 'new' => __( 'New', 'tiboform' ), 'read' => __( 'Read', 'tiboform' ), 'replied' => __( 'Replied', 'tiboform' ), 'spam' => __( 'Spam', 'tiboform' ), ); } /** * Başvurunun durumu. * * @param int $id Başvuru. * @return string */ function tiboform_entry_status( $id ) { $s = (string) get_post_meta( $id, '_tiboform_status', true ); if ( '' === $s ) { $s = (int) get_post_meta( $id, '_tiboform_read', true ) ? 'read' : 'new'; } return isset( tiboform_statuses()[ $s ] ) ? $s : 'new'; } /** * KVKK: saklama süresi dolan başvuruları sil. */ add_action( 'tiboform_cleanup', function () { foreach ( get_posts( array( 'post_type' => 'tiboform_form', 'posts_per_page' => 200, 'fields' => 'ids' ) ) as $fid ) { $f = tiboform_form( $fid ); $d = (int) $f['settings']['keep_days']; if ( $d < 1 ) { continue; } foreach ( get_posts( array( 'post_type' => 'tiboform_entry', 'post_parent' => $fid, 'posts_per_page' => 500, 'fields' => 'ids', 'date_query' => array( array( 'before' => $d . ' days ago' ) ) ) ) as $eid ) { wp_delete_post( $eid, true ); } } } );