Files

403 lines
15 KiB
PHP

<?php
/**
* Form Handler Class
*
* Handles form submission, validation, and storage.
*
* @package PCFormBuilder
*/
class PC_Form_Handler {
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action( 'wp_ajax_pcfb_submit_form', array( $this, 'handle_form_submission' ) );
add_action( 'wp_ajax_nopriv_pcfb_submit_form', array( $this, 'handle_form_submission' ) );
add_action( 'wp_ajax_pcfb_add_field', array( $this, 'handle_add_field' ) );
add_shortcode( 'pcfb-form', array( $this, 'shortcode_form' ) );
}
public function handle_add_field() {
check_ajax_referer( 'pcfb_admin_nonce', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( 'Permission denied.', 'pc-form-builder-xyz123' ) ) );
}
$field_type = isset( $_POST['field_type'] ) ? sanitize_text_field( $_POST['field_type'] ) : '';
$field_index = isset( $_POST['field_index'] ) ? intval( $_POST['field_index'] ) : 0;
if ( empty( $field_type ) ) {
wp_send_json_error( array( 'message' => __( 'Field type is required.', 'pc-form-builder-xyz123' ) ) );
}
require_once PCFB_PLUGIN_DIR . 'admin/class-admin-helper.php';
$helper = PCFB_Admin_Helper::get_instance();
ob_start();
$helper->render_new_field_item( $field_type, $field_index );
$html = ob_get_clean();
wp_send_json_success( array( 'html' => $html ) );
}
public function shortcode_form( $atts ) {
$atts = shortcode_atts( array(
'id' => 0,
), $atts );
if ( empty( $atts['id'] ) ) {
return '<p>' . esc_html__( 'Form ID is required.', 'pc-form-builder-xyz123' ) . '</p>';
}
$form = $this->get_form( intval( $atts['id'] ) );
if ( ! $form ) {
return '<p>' . esc_html__( 'Form not found.', 'pc-form-builder-xyz123' ) . '</p>';
}
if ( 'active' !== $form->status ) {
return '<p>' . esc_html__( 'This form is not currently active.', 'pc-form-builder-xyz123' ) . '</p>';
}
$fields = $this->get_form_fields( $form->id );
$settings = maybe_unserialize( $form->settings );
ob_start();
include PCFB_PLUGIN_DIR . 'public/templates/form-display.php';
return ob_get_clean();
}
private function get_form( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE id = %d", $form_id ) );
}
private function get_form_fields( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ) );
}
public function handle_form_submission() {
check_ajax_referer( 'pcfb_public_nonce', 'nonce' );
$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
$form_data = isset( $_POST['form_data'] ) ? $_POST['form_data'] : array();
if ( empty( $form_id ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid form ID.', 'pc-form-builder-xyz123' ) ) );
}
$form = $this->get_form( $form_id );
if ( ! $form ) {
wp_send_json_error( array( 'message' => __( 'Form not found.', 'pc-form-builder-xyz123' ) ) );
}
$fields = $this->get_form_fields( $form_id );
$errors = array();
$clean_data = array();
foreach ( $fields as $field ) {
$value = isset( $form_data[ $field->field_name ] ) ? trim( $form_data[ $field->field_name ] ) : '';
$validation_rules = maybe_unserialize( $field->validation_rules );
if ( ! empty( $validation_rules['required'] ) && empty( $value ) ) {
$errors[ $field->field_name ] = sprintf(
__( '%s is required.', 'pc-form-builder-xyz123' ),
$field->field_label
);
}
if ( ! empty( $value ) && 'email' === $field->field_type ) {
if ( ! is_email( $value ) ) {
$errors[ $field->field_name ] = __( 'Please enter a valid email address.', 'pc-form-builder-xyz123' );
}
}
$clean_data[ $field->id ] = sanitize_text_field( $value );
}
if ( ! empty( $errors ) ) {
wp_send_json_error( array( 'message' => __( 'Please fix the errors below.', 'pc-form-builder-xyz123' ), 'errors' => $errors ) );
}
$response_id = $this->save_response( $form_id, $clean_data );
if ( $response_id ) {
$success_message = ! empty( $settings['success_message'] )
? $settings['success_message']
: __( 'Thank you! Your response has been submitted.', 'pc-form-builder-xyz123' );
wp_send_json_success( array( 'message' => $success_message, 'response_id' => $response_id ) );
} else {
wp_send_json_error( array( 'message' => __( 'Failed to save your response. Please try again.', 'pc-form-builder-xyz123' ) ) );
}
}
private function save_response( $form_id, $field_data ) {
global $wpdb;
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$user_ip = $_SERVER['REMOTE_ADDR'] ?? '';
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$wpdb->insert(
$responses_table,
array(
'form_id' => $form_id,
'user_ip' => $user_ip,
'user_agent'=> $user_agent,
'status' => 'new',
)
);
if ( ! $wpdb->insert_id ) {
return false;
}
$response_id = $wpdb->insert_id;
foreach ( $field_data as $field_id => $value ) {
$wpdb->insert(
$response_data_table,
array(
'response_id' => $response_id,
'field_id' => $field_id,
'field_value' => $value,
)
);
}
return $response_id;
}
public static function get_forms( $args = array() ) {
global $wpdb;
$defaults = array(
'status' => 'active',
'orderby' => 'created_at',
'order' => 'DESC',
'limit' => -1,
);
$args = wp_parse_args( $args, $defaults );
$table_name = $wpdb->prefix . 'pcfb_forms';
$sql = "SELECT * FROM {$table_name}";
if ( ! empty( $args['status'] ) ) {
$sql .= $wpdb->prepare( " WHERE status = %s", $args['status'] );
}
$sql .= " ORDER BY {$args['orderby']} {$args['order']}";
if ( $args['limit'] > 0 ) {
$sql .= $wpdb->prepare( " LIMIT %d", $args['limit'] );
}
return $wpdb->get_results( $sql );
}
public static function get_form_by_id( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE id = %d", $form_id ) );
}
public static function get_form_count( $status = 'active' ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_forms';
return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE status = %s", $status ) );
}
public static function get_form_response_count( $form_id ) {
global $wpdb;
$table_name = $wpdb->prefix . 'pcfb_responses';
return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table_name} WHERE form_id = %d", $form_id ) );
}
public static function get_form_responses( $form_id, $args = array() ) {
global $wpdb;
$defaults = array(
'limit' => 20,
'offset' => 0,
'orderby' => 'created_at',
'order' => 'DESC',
);
$args = wp_parse_args( $args, $defaults );
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$sql = $wpdb->prepare(
"SELECT r.* FROM {$responses_table} r
WHERE r.form_id = %d
ORDER BY r.{$args['orderby']} {$args['order']}
LIMIT %d OFFSET %d",
$form_id,
$args['limit'],
$args['offset']
);
return $wpdb->get_results( $sql );
}
public static function get_response_data( $response_id ) {
global $wpdb;
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$fields_table = $wpdb->prefix . 'pcfb_fields';
return $wpdb->get_results(
$wpdb->prepare(
"SELECT rd.*, f.field_name, f.field_label, f.field_type
FROM {$response_data_table} rd
JOIN {$fields_table} f ON rd.field_id = f.id
WHERE rd.response_id = %d",
$response_id
)
);
}
public static function delete_form( $form_id ) {
global $wpdb;
$forms_table = $wpdb->prefix . 'pcfb_forms';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$responses_table = $wpdb->prefix . 'pcfb_responses';
$response_data_table = $wpdb->prefix . 'pcfb_response_data';
$response_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$responses_table} WHERE form_id = %d", $form_id ) );
if ( ! empty( $response_ids ) ) {
$response_ids_placeholder = implode( ',', array_map( 'intval', $response_ids ) );
$wpdb->query( "DELETE FROM {$response_data_table} WHERE response_id IN ({$response_ids_placeholder})" );
$wpdb->query( "DELETE FROM {$responses_table} WHERE form_id = {$form_id}" );
}
$wpdb->query( "DELETE FROM {$fields_table} WHERE form_id = {$form_id}" );
return $wpdb->delete( $forms_table, array( 'id' => $form_id ) );
}
public function save_form( $data, $fields = array() ) {
global $wpdb;
$forms_table = $wpdb->prefix . 'pcfb_forms';
$fields_table = $wpdb->prefix . 'pcfb_fields';
$form_data = array(
'name' => sanitize_text_field( $data['name'] ),
'description' => sanitize_text_field( $data['description'] ),
'settings' => maybe_serialize( isset( $data['settings'] ) ? $data['settings'] : array() ),
'status' => isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'active',
);
if ( ! empty( $data['id'] ) ) {
$form_id = intval( $data['id'] );
$wpdb->update( $forms_table, $form_data, array( 'id' => $form_id ) );
$existing_fields = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$fields_table} WHERE form_id = %d", $form_id ) );
$existing_field_ids = ! empty( $existing_fields ) ? array_map( 'intval', $existing_fields ) : array();
$submitted_field_ids = array();
$sort_order = 0;
if ( ! empty( $fields ) && is_array( $fields ) ) {
foreach ( $fields as $field ) {
$field_data = array(
'form_id' => $form_id,
'field_type' => sanitize_text_field( $field['field_type'] ),
'field_label' => sanitize_text_field( $field['field_label'] ),
'field_name' => $this->generate_field_name( $field['field_label'], $form_id, isset( $field['id'] ) ? $field['id'] : 0 ),
'placeholder' => isset( $field['placeholder'] ) ? sanitize_text_field( $field['placeholder'] ) : '',
'options' => isset( $field['options'] ) ? maybe_serialize( $field['options'] ) : '',
'validation_rules' => isset( $field['validation_rules'] ) ? maybe_serialize( $field['validation_rules'] ) : '',
'sort_order' => $sort_order++,
);
if ( ! empty( $field['id'] ) ) {
$submitted_field_ids[] = intval( $field['id'] );
$wpdb->update( $fields_table, $field_data, array( 'id' => intval( $field['id'] ) ) );
} else {
$wpdb->insert( $fields_table, $field_data );
$submitted_field_ids[] = $wpdb->insert_id;
}
}
}
foreach ( $existing_field_ids as $field_id ) {
if ( ! in_array( $field_id, $submitted_field_ids ) ) {
$wpdb->delete( $fields_table, array( 'id' => $field_id ) );
}
}
return $form_id;
} else {
$wpdb->insert( $forms_table, $form_data );
$form_id = $wpdb->insert_id;
if ( $form_id && ! empty( $fields ) && is_array( $fields ) ) {
$sort_order = 0;
foreach ( $fields as $field ) {
$field_data = array(
'form_id' => $form_id,
'field_type' => sanitize_text_field( $field['field_type'] ),
'field_label' => sanitize_text_field( $field['field_label'] ),
'field_name' => $this->generate_field_name( $field['field_label'], $form_id ),
'placeholder' => isset( $field['placeholder'] ) ? sanitize_text_field( $field['placeholder'] ) : '',
'options' => isset( $field['options'] ) ? maybe_serialize( $field['options'] ) : '',
'validation_rules' => isset( $field['validation_rules'] ) ? maybe_serialize( $field['validation_rules'] ) : '',
'sort_order' => $sort_order++,
);
$wpdb->insert( $fields_table, $field_data );
}
}
return $form_id;
}
}
private function generate_field_name( $label, $form_id, $existing_id = 0 ) {
$base_name = sanitize_title( $label );
$base_name = preg_replace( '/[^a-z0-9_]/', '', strtolower( $base_name ) );
if ( empty( $base_name ) ) {
$base_name = 'field_' . time();
}
global $wpdb;
$fields_table = $wpdb->prefix . 'pcfb_fields';
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$fields_table} WHERE form_id = %d AND field_name LIKE %s",
$form_id,
$base_name . '%'
);
$count = $wpdb->get_var( $query );
if ( $count > 0 ) {
return $base_name . '_' . ( $count + 1 );
}
return $base_name;
}
}