feat: add form builder AJAX handlers (F2.11)

- Create FormBuilderAjax class for React form builder
- Add formipay_save_form_fields AJAX action
- Add formipay_load_form_fields AJAX action
- Sanitize field data on save
- Update FormBuilder to load fields on mount
- Add save status feedback (saving, saved, error)
- Register FormBuilderAjax singleton in main plugin file
This commit is contained in:
dwindown
2026-04-18 11:41:10 +07:00
parent ec1f01ef24
commit 7f50b27df3
3 changed files with 167 additions and 6 deletions

View File

@@ -0,0 +1,127 @@
<?php
namespace Formipay\Admin;
use Formipay\Traits\SingletonTrait;
if ( ! defined( 'ABSPATH' ) ) exit;
/**
* AJAX handlers for React Form Builder
*/
class FormBuilderAjax {
use SingletonTrait;
protected function __construct() {
add_action( 'wp_ajax_formipay_save_form_fields', [$this, 'save_form_fields'] );
add_action( 'wp_ajax_formipay_load_form_fields', [$this, 'load_form_fields'] );
}
/**
* Save form fields via AJAX
*/
public function save_form_fields() {
check_ajax_referer( 'formipay-admin', '_wpnonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => '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;
}
}