diff --git a/formipay.php b/formipay.php index f7cd3d2f4..3a2f6c0f9 100644 --- a/formipay.php +++ b/formipay.php @@ -50,6 +50,7 @@ spl_autoload_register(function ($class) { \Formipay\Init::get_instance(); \Formipay\Admin\ReactAdmin::get_instance(); +\Formipay\Admin\FormBuilderAjax::get_instance(); register_activation_hook( __FILE__, 'formipay_activate' ); function formipay_activate() { diff --git a/includes/Admin/FormBuilderAjax.php b/includes/Admin/FormBuilderAjax.php new file mode 100644 index 000000000..37bb9ab75 --- /dev/null +++ b/includes/Admin/FormBuilderAjax.php @@ -0,0 +1,127 @@ + 'Unauthorized' ] ); + } + + $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; + $fields_json = isset( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : '[]'; + + if ( $post_id === 0 ) { + wp_send_json_error( [ 'message' => 'Invalid post ID' ] ); + } + + $fields = json_decode( $fields_json, true ); + + if ( json_last_error() !== JSON_ERROR_NONE ) { + wp_send_json_error( [ 'message' => 'Invalid JSON data' ] ); + } + + // Sanitize fields + $sanitized_fields = []; + foreach ( $fields as $field ) { + $sanitized_fields[] = $this->sanitize_field( $field ); + } + + // Update post meta + $current_settings = get_post_meta( $post_id, 'formipay_settings', true ); + $current_settings = is_array( $current_settings ) ? $current_settings : []; + + $current_settings['fields'] = $sanitized_fields; + + update_post_meta( $post_id, 'formipay_settings', $current_settings ); + + wp_send_json_success( [ + 'message' => 'Form fields saved successfully', + 'fields' => $sanitized_fields + ] ); + + } + + /** + * Load form fields via AJAX + */ + public function load_form_fields() { + + check_ajax_referer( 'formipay-admin', '_wpnonce' ); + + if ( ! current_user_can( 'edit_posts' ) ) { + wp_send_json_error( [ 'message' => 'Unauthorized' ] ); + } + + $post_id = isset( $_GET['post_id'] ) ? intval( $_GET['post_id'] ) : 0; + + if ( $post_id === 0 ) { + wp_send_json_error( [ 'message' => 'Invalid post ID' ] ); + } + + $settings = get_post_meta( $post_id, 'formipay_settings', true ); + $fields = isset( $settings['fields'] ) ? $settings['fields'] : []; + + wp_send_json_success( [ + 'fields' => $fields + ] ); + + } + + /** + * Sanitize a single field + */ + private function sanitize_field( $field ) { + + $sanitized = [ + 'field_type' => sanitize_text_field( $field['field_type'] ?? 'text' ), + 'label' => sanitize_text_field( $field['label'] ?? '' ), + 'field_id' => sanitize_title( str_replace( ' ', '_', $field['field_id'] ?? '' ) ), + 'placeholder' => sanitize_text_field( $field['placeholder'] ?? '' ), + 'default_value' => sanitize_text_field( $field['default_value'] ?? '' ), + 'description' => sanitize_textarea_field( $field['description'] ?? '' ), + 'is_required' => (bool) ( $field['is_required'] ?? false ), + 'option_grid_columns' => absint( $field['option_grid_columns'] ?? 1 ), + 'field_options' => [], + ]; + + // Sanitize field options + if ( isset( $field['field_options'] ) && is_array( $field['field_options'] ) ) { + foreach ( $field['field_options'] as $option ) { + $sanitized['field_options'][] = [ + 'label' => sanitize_text_field( $option['label'] ?? '' ), + 'value' => sanitize_text_field( $option['value'] ?? '' ), + 'amount' => floatval( $option['amount'] ?? 0 ), + 'weight' => floatval( $option['weight'] ?? 0 ), + 'quantity' => (bool) ( $option['quantity'] ?? false ), + 'thumbnail' => absint( $option['thumbnail'] ?? 0 ), + ]; + } + } + + return $sanitized; + + } + +} diff --git a/src/admin/components/formBuilder/FormBuilder.js b/src/admin/components/formBuilder/FormBuilder.js index 2394c9ab5..5a1dc5530 100644 --- a/src/admin/components/formBuilder/FormBuilder.js +++ b/src/admin/components/formBuilder/FormBuilder.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; -import { useState, useCallback } from '@wordpress/element'; +import { useState, useCallback, useEffect } from '@wordpress/element'; import FormCanvas from './FormCanvas'; import FieldPalette from './FieldPalette'; import FieldSettingsPanel from './FieldSettingsPanel'; @@ -13,9 +13,36 @@ import './FormBuilder.css'; export default function FormBuilder({ formId, initialData = {} }) { const [fields, setFields] = useState(initialData.fields || []); const [selectedFieldId, setSelectedFieldId] = useState(null); + const [saveStatus, setSaveStatus] = useState(null); const selectedField = fields.find(f => f.field_id === selectedFieldId) || null; + // Load existing fields on mount + useEffect(() => { + if (formId && !initialData.fields) { + loadFields(); + } + }, [formId]); + + const loadFields = useCallback(() => { + const params = new URLSearchParams({ + action: 'formipay_load_form_fields', + post_id: formId, + _wpnonce: window.formipayAdmin?.nonce || '', + }); + + fetch(`${window.formipayAdmin?.ajaxUrl || '/wp-admin/admin-ajax.php'}?${params}`) + .then(response => response.json()) + .then(result => { + if (result.success && result.data.fields) { + setFields(result.data.fields); + } + }) + .catch(error => { + console.error('Load error:', error); + }); + }, [formId]); + const handleDrop = useCallback((newField) => { setFields([...fields, newField]); setSelectedFieldId(newField.field_id); @@ -42,7 +69,7 @@ export default function FormBuilder({ formId, initialData = {} }) { }, [fields, selectedFieldId]); const handleSave = useCallback(() => { - // Save form fields via AJAX + setSaveStatus('saving'); const formData = new FormData(); formData.append('action', 'formipay_save_form_fields'); formData.append('post_id', formId); @@ -57,13 +84,15 @@ export default function FormBuilder({ formId, initialData = {} }) { .then(response => response.json()) .then(result => { if (result.success) { - // Show success message - console.log('Form saved successfully'); + setSaveStatus('saved'); + setTimeout(() => setSaveStatus(null), 2000); } else { + setSaveStatus('error'); console.error('Failed to save form:', result.message); } }) .catch(error => { + setSaveStatus('error'); console.error('Save error:', error); }); }, [fields, formId]); @@ -82,10 +111,14 @@ export default function FormBuilder({ formId, initialData = {} }) {