Complete React-based field rendering system that replaces WPCFTO Vue.js layer while maintaining PHP field configuration compatibility. Components: - FieldRenderer: Main renderer with tabs support (metabox) and direct mode (settings) - FieldTypes: 15+ field types (Text, Number, Select, Radio, Date, etc.) - RepeaterField: Collapsible repeater with currency label parsing - DependencyEngine: Show/hide fields based on conditions - ValidationEngine: Client-side validation with error messages - SettingsRenderer: Settings page with AJAX save to wp_options Features: - Repeater rows collapsed by default with readable currency titles - Searchable dropdowns using Popover + Command pattern - Proper label resolution for pre-selected values - Hidden input sync for WordPress form submission Also includes: - FieldConfigBridge: Transform PHP configs to React format - Updated Settings.php for React-based settings page - Radio-group UI component - wp-admin-restore.css for admin panel isolation
407 lines
16 KiB
PHP
407 lines
16 KiB
PHP
<?php
|
|
namespace Formipay;
|
|
use Formipay\Traits\SingletonTrait;
|
|
use Formipay\Admin\FieldConfigBridge;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) exit;
|
|
|
|
class Settings {
|
|
|
|
use SingletonTrait;
|
|
|
|
/**
|
|
* Initializes the plugin by setting filters and administration functions.
|
|
*/
|
|
|
|
protected function __construct() {
|
|
|
|
// Register our submenu page
|
|
add_action( 'admin_menu', [$this, 'add_settings_page'] );
|
|
|
|
add_action( 'admin_enqueue_scripts', [$this, 'enqueue'] );
|
|
add_action( 'admin_footer', [$this, 'render_react_settings_template'] );
|
|
|
|
// AJAX handler for saving settings from React
|
|
add_action( 'wp_ajax_formipay_save_settings', [$this, 'ajax_save_settings'] );
|
|
|
|
}
|
|
|
|
/**
|
|
* Add settings submenu page
|
|
*/
|
|
public function add_settings_page() {
|
|
add_submenu_page(
|
|
'formipay', // Parent slug
|
|
__('Formipay Settings', 'formipay'), // Page title
|
|
__('Settings', 'formipay'), // Menu title
|
|
'manage_options', // Capability
|
|
'formipay-settings', // Menu slug
|
|
[$this, 'render_settings_page'] // Callback function
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get settings field configuration for React
|
|
* Direct method without WPCFTO dependency
|
|
*/
|
|
public function get_settings_fields() {
|
|
$gateways = apply_filters( 'formipay/form-config/tab:payments/gateways', [] );
|
|
|
|
$payment_checkboxes = [];
|
|
if(!empty($gateways)){
|
|
foreach($gateways as $gateway){
|
|
$id = $gateway['id'];
|
|
$label = $gateway['gateway'];
|
|
if(isset($gateway['channel'])){
|
|
$label .= ' - '.$gateway['channel'];
|
|
}
|
|
$payment_checkboxes[$id] = $label;
|
|
}
|
|
}
|
|
|
|
$general_fields = array(
|
|
'business_group' => array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Business', 'formipay' ),
|
|
'group' => 'started'
|
|
),
|
|
'business_name' => array(
|
|
'type' => 'text',
|
|
'label' => __( 'Business Name', 'formipay' ),
|
|
'description' => __( 'This may be displayed on payment gateway like Paypal as a merchant name.', 'formipay' ),
|
|
'required' => true,
|
|
'group' => 'ended'
|
|
),
|
|
'currency_group' => array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Currency', 'formipay' ),
|
|
'group' => 'started'
|
|
),
|
|
'enable_multicurrency' => [
|
|
'type' => 'checkbox',
|
|
'label' => __( 'Enable Multi Currency', 'formipay' )
|
|
],
|
|
'enable_auto_exchangerate' => [
|
|
'type' => 'checkbox',
|
|
'label' => __( 'Enable Auto Exchange Rate', 'formipay' ),
|
|
'dependency' => [
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'not_empty'
|
|
]
|
|
],
|
|
'enable_auto_exchangerate_apikey' => [
|
|
'type' => 'text',
|
|
'label' => __( 'Auto Exchange Rate API Key', 'formipay' ),
|
|
'required' => true,
|
|
'dependency' => [
|
|
[
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'not_empty'
|
|
],
|
|
[
|
|
'key' => 'enable_auto_exchangerate',
|
|
'value' => 'not_empty'
|
|
]
|
|
],
|
|
'dependencies' => '&&'
|
|
],
|
|
'multicurrencies' => [
|
|
'type' => 'repeater',
|
|
'label' => __( 'Currencies', 'formipay' ),
|
|
'fields' => [
|
|
'currency' => array(
|
|
'type' => 'select',
|
|
'label' => __('Default Currency', 'formipay'),
|
|
'value' => 'IDR:::Indonesian rupiah:::Rp',
|
|
'options' => formipay_currency_as_options(),
|
|
'required' => true,
|
|
'searchable' => true,
|
|
'is_group_title' => true
|
|
),
|
|
'decimal_digits' => array(
|
|
'type' => 'number',
|
|
'label' => __('Decimal Digits', 'formipay'),
|
|
'value' => '2',
|
|
'required' => true,
|
|
),
|
|
'decimal_symbol' => array(
|
|
'type' => 'text',
|
|
'label' => __('Decimal Symbol', 'formipay'),
|
|
'value' => '.',
|
|
'required' => true,
|
|
),
|
|
'thousand_separator' => array(
|
|
'type' => 'text',
|
|
'label' => __('Thousand Separator Symbol', 'formipay'),
|
|
'value' => ',',
|
|
'required' => true,
|
|
),
|
|
'payment_gateways' => array(
|
|
'type' => 'multi_checkbox',
|
|
'label' => __( 'Payment Gateways', 'formipay' ),
|
|
'options' => $payment_checkboxes,
|
|
'submenu' => __( 'General', 'formipay' ),
|
|
),
|
|
'exchange_rate' => array(
|
|
'type' => 'number',
|
|
'label' => __( 'Manual Exchange Rate', 'formipay' ),
|
|
'description' => __( 'This value is the exchange rate of default currency against this currency. If this currency selected, total order will be multiplied to this value. <b>This override the value from ExchangeRatePI if enabled</b>', 'formipay' ),
|
|
'submenu' => __( 'General', 'formipay' ),
|
|
)
|
|
],
|
|
'required' => true,
|
|
'dependency' => [
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'not_empty'
|
|
]
|
|
],
|
|
'default_currency' => array(
|
|
'type' => 'select',
|
|
'label' => __('Default Currency', 'formipay'),
|
|
'value' => 'IDR:::Indonesian rupiah:::Rp',
|
|
'options' => formipay_currency_as_options(),
|
|
'required' => true,
|
|
'searchable' => true
|
|
),
|
|
'default_currency_decimal_digits' => array(
|
|
'type' => 'number',
|
|
'label' => __('Decimal Digits', 'formipay'),
|
|
'value' => '2',
|
|
'required' => true,
|
|
'dependency' => [
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'empty'
|
|
]
|
|
),
|
|
'default_currency_decimal_symbol' => array(
|
|
'type' => 'text',
|
|
'label' => __('Decimal Symbol', 'formipay'),
|
|
'value' => '.',
|
|
'required' => true,
|
|
'dependency' => [
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'empty'
|
|
]
|
|
),
|
|
'default_currency_thousand_separator' => array(
|
|
'type' => 'text',
|
|
'label' => __('Thousand Separator Symbol', 'formipay'),
|
|
'value' => ',',
|
|
'required' => true,
|
|
'dependency' => [
|
|
'key' => 'enable_multicurrency',
|
|
'value' => 'empty'
|
|
],
|
|
'group' => 'ended'
|
|
),
|
|
);
|
|
|
|
$general_fields = apply_filters( 'formipay/global-settings/tab:general', $general_fields );
|
|
|
|
$pages_fields = array(
|
|
|
|
'thankyou_page_group' => array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Thank-You Page Style', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'group' => 'started'
|
|
),
|
|
'thankyou_link' => array(
|
|
'type' => 'text',
|
|
'label' => __( 'Thank-You Page Link', 'formipay' ),
|
|
'value' => 'thankyou',
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'required' => true
|
|
),
|
|
'thankyou_style' => array(
|
|
'type' => 'image_select',
|
|
'label' => esc_html__( 'Style', 'formipay' ),
|
|
'width' => 100,
|
|
'height' => 100,
|
|
'value' => 'receipt',
|
|
'options' => array(
|
|
'card' => array(
|
|
'alt' => 'Card',
|
|
'img' => FORMIPAY_URL . 'admin/assets/img/thankyou_card_style.png'
|
|
),
|
|
'receipt' => array(
|
|
'alt' => 'Receipt',
|
|
'img' => FORMIPAY_URL . 'admin/assets/img/thankyou_receipt_style.png'
|
|
),
|
|
),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'required' => true
|
|
),
|
|
'thankyou_page_container_bg_color' => array(
|
|
'type' => 'color',
|
|
'label' => __( 'Container Background Color', 'formipay' ),
|
|
'value' => '#808080',
|
|
'description' => __( 'Container is the main div on Thank-You Page contents', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
),
|
|
'thankyou_page_wrapper_bg_color' => array(
|
|
'type' => 'color',
|
|
'label' => __( 'Wrapper Background Color', 'formipay' ),
|
|
'value' => '#ffffff',
|
|
'description' => __( 'Wrapper is the div that fit to Thank-You Page contents width', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
),
|
|
'thankyou_page_wrapper_max_width' => array(
|
|
'type' => 'number',
|
|
'label' => __( 'Wrapper Max Width', 'formipay' ),
|
|
'value' => '600',
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'group' => 'ended',
|
|
'required' => true
|
|
),
|
|
'thankyou_page_restriction_group' => array(
|
|
'type' => 'group_title',
|
|
'label' => __( 'Restriction Access', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'group' => 'started'
|
|
),
|
|
'thankyou_page_restriction_thumbnail' => array(
|
|
'type' => 'image',
|
|
'label' => __( 'Thumbnail', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' )
|
|
),
|
|
'thankyou_page_restriction_title' => array(
|
|
'type' => 'text',
|
|
'label' => __( 'Title', 'formipay' ),
|
|
'value' => __( 'Request to Access', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' )
|
|
),
|
|
'thankyou_page_restriction_message' => array(
|
|
'type' => 'hint_textarea',
|
|
'label' => __( 'Message', 'formipay' ),
|
|
'value' => __( 'Input your {{media}} to get new access link.', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'hints' => array(
|
|
'media' => __( 'Contact Media', 'formipay' )
|
|
),
|
|
'description' => __( 'Use {{media}} shortcode to define what media of contact the buyer can receive the access link.', 'formipay' )
|
|
),
|
|
'thankyou_page_restriction_button' => array(
|
|
'type' => 'text',
|
|
'label' => __( 'Request Access Button', 'formipay' ),
|
|
'value' => __( 'Get Access Link', 'formipay' ),
|
|
'submenu' => __( 'Thank-You Page', 'formipay' ),
|
|
'group' => 'ended'
|
|
)
|
|
);
|
|
|
|
$pages_fields = apply_filters( 'formipay/global-settings/tab:pages', $pages_fields );
|
|
|
|
$tabs_config = [
|
|
'General' => [
|
|
'name' => __( 'General', 'formipay' ),
|
|
'fields' => $general_fields
|
|
],
|
|
'Pages' => [
|
|
'name' => __( 'Pages', 'formipay' ),
|
|
'fields' => $pages_fields
|
|
]
|
|
];
|
|
|
|
// Allow other modules to add/modify tabs
|
|
$tabs_config = apply_filters( 'formipay/global-settings', $tabs_config );
|
|
|
|
return $tabs_config;
|
|
}
|
|
|
|
/**
|
|
* Render settings page (empty container for React)
|
|
*/
|
|
public function render_settings_page() {
|
|
?>
|
|
<div class="wrap">
|
|
<div id="formipay-settings-page-container"></div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
public function enqueue() {
|
|
|
|
global $current_screen;
|
|
|
|
if ( $current_screen->id === 'formipay_page_formipay-settings' ) {
|
|
// Enqueue React admin assets for FieldRenderer
|
|
wp_enqueue_script( 'formipay-admin', FORMIPAY_URL . 'build/admin.js', ['react', 'react-dom'], FORMIPAY_VERSION, true );
|
|
wp_enqueue_style( 'formipay-admin', FORMIPAY_URL . 'build/admin.css', [], FORMIPAY_VERSION, 'all' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Render React settings template in admin footer
|
|
* This outputs the config JSON and mount point for the React FieldRenderer
|
|
*/
|
|
public function render_react_settings_template() {
|
|
global $current_screen;
|
|
|
|
// Only render on settings page
|
|
if ( $current_screen->id !== 'formipay_page_formipay-settings' ) {
|
|
return;
|
|
}
|
|
|
|
// Get the configuration for settings
|
|
$config = FieldConfigBridge::get_config_for_settings('formipay_settings');
|
|
$config_json = wp_json_encode($config);
|
|
|
|
?>
|
|
<div id="formipay-settings-react" data-formipay-settings-config="<?php echo esc_attr($config_json); ?>"></div>
|
|
<script>
|
|
// Move the React mount point to our page container
|
|
jQuery(document).ready(function($) {
|
|
$('#formipay-settings-react').appendTo('#formipay-settings-page-container');
|
|
});
|
|
</script>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for saving settings from React
|
|
*/
|
|
public function ajax_save_settings() {
|
|
// Verify nonce
|
|
check_ajax_referer( 'formipay-field-config', 'nonce', true );
|
|
|
|
// Check permissions
|
|
if (!current_user_can('manage_options')) {
|
|
wp_send_json_error([
|
|
'message' => __( 'You do not have permission to save settings.', 'formipay' )
|
|
]);
|
|
}
|
|
|
|
// Get settings data
|
|
$settings = isset($_POST['settings']) ? json_decode(sanitize_text_field(wp_unslash($_POST['settings'])), true) : [];
|
|
|
|
if (empty($settings)) {
|
|
wp_send_json_error([
|
|
'message' => __( 'No settings data received.', 'formipay' )
|
|
]);
|
|
}
|
|
|
|
// Remove nonce from settings before saving
|
|
unset($settings['nonce']);
|
|
|
|
// Get existing settings
|
|
$existing_settings = get_option('formipay_settings', []);
|
|
|
|
// Merge with existing settings to preserve values not in current form
|
|
$updated_settings = array_merge($existing_settings, $settings);
|
|
|
|
// Update option
|
|
$result = update_option('formipay_settings', $updated_settings);
|
|
|
|
if ($result) {
|
|
wp_send_json_success([
|
|
'message' => __( 'Settings saved successfully.', 'formipay' )
|
|
]);
|
|
} else {
|
|
wp_send_json_error([
|
|
'message' => __( 'Failed to save settings.', 'formipay' )
|
|
]);
|
|
}
|
|
}
|
|
|
|
}
|