load_settings(); add_action('woocommerce_blocks_loaded', array($this, 'register_checkout_field_block')); add_filter('woocommerce_blocks_checkout_fields_locations', array($this, 'add_custom_fields_location')); add_filter('woocommerce_blocks_checkout_fields', array($this, 'register_checkout_fields_for_blocks')); add_filter('render_block_woocommerce/checkout', array($this, 'modify_checkout_block'), 10, 2); add_action('woocommerce_store_api_checkout_update_order_from_request', array($this, 'save_block_fields_from_request'), 10, 2); add_action('woocommerce_checkout_update_order_meta', array($this, 'save_block_fields'), 10, 2); add_action('woocommerce_store_api_checkout_update_order_meta', array($this, 'save_block_fields'), 10, 1); add_action('woocommerce_checkout_order_processed', array($this, 'save_fields_on_order_processed'), 10, 3); add_action('woocommerce_new_order', array($this, 'save_fields_on_new_order'), 10, 1); add_action('wp_ajax_enspireplugins_acfw_save_checkout_data', array($this, 'ajax_save_checkout_data')); add_action('wp_ajax_nopriv_enspireplugins_acfw_save_checkout_data', array($this, 'ajax_save_checkout_data')); if (!self::$hooks_registered) { self::$hooks_registered = true; } } public function add_custom_fields_location($locations) { $locations['additional-fields'] = array( 'address' => 'contact', 'priority' => 45, ); return $locations; } public function register_checkout_field_block() { if (!class_exists('\Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields')) { add_action('woocommerce_checkout_billing', array($this, 'render_fields_in_checkout'), 25); return; } add_filter('woocommerce_blocks_checkout_fields', array($this, 'register_checkout_fields_for_blocks')); } public function register_checkout_fields_for_blocks($fields) { $active_fields = $this->get_active_fields(); if (empty($active_fields)) { return $fields; } foreach ($active_fields as $field) { if ($field['type'] === 'heading') { continue; } $field_id = 'enspireplugins_acfw_' . $field['id']; $field_config = array( 'id' => $field_id, 'label' => $field['label'], 'type' => $this->map_field_type_for_blocks($field['type']), 'required' => isset($field['required']) && $field['required'] === 'yes', 'placeholder' => isset($field['placeholder']) ? $field['placeholder'] : '', 'location' => 'additional-fields', 'priority' => 45, 'hidden' => false, 'auto_inserted' => true, ); if ($field['type'] === 'select' || $field['type'] === 'radio') { $field_config['options'] = $this->process_field_options($field); } $fields[$field_id] = $field_config; } return $fields; } public function modify_checkout_block($block_content, $block) { $active_fields = $this->get_active_fields(); if (empty($active_fields)) { return $block_content; } if (strpos($block_content, 'enspireplugins_acfw_auto_fields') !== false) { return $block_content; } $payment_pattern = '/(]*class="[^"]*wp-block-woocommerce-checkout-payment-block[^"]*"[^>]*>)/'; if (preg_match($payment_pattern, $block_content)) { $custom_fields_html = $this->generate_checkout_fields_html(); $block_content = preg_replace( $payment_pattern, $custom_fields_html . '$1', $block_content ); } return $block_content; } private function generate_checkout_fields_html() { $active_fields = $this->get_active_fields(); if (empty($active_fields)) { return ''; } ob_start(); ?>
render_checkout_field($field); ?>
render_heading_field($field); break; case 'text': case 'number': case 'email': case 'url': $this->render_text_input_field($field); break; case 'textarea': $this->render_textarea_field($field); break; case 'select': $this->render_select_field($field); break; case 'checkbox': $this->render_checkbox_field($field); break; case 'radio': $this->render_radio_field($field); break; } } protected function render_heading_field($field) { echo '
'; echo '

' . esc_html($field['label']) . '

'; echo '
'; } private function render_text_input_field($field) { $field_id = 'enspireplugins_acfw_' . $field['id']; $is_required = isset($field['required']) && $field['required'] === 'yes'; $placeholder = isset($field['placeholder']) ? $field['placeholder'] : ''; $label = $field['label']; $type = $field['type']; $css_classes = array( 'wc-block-components-text-input', 'enspireplugins_acfw-field' ); if ($is_required) { $css_classes[] = 'is-required'; } echo '
'; echo ''; echo ''; echo '
'; } private function render_textarea_field($field) { $field_id = 'enspireplugins_acfw_' . $field['id']; $is_required = isset($field['required']) && $field['required'] === 'yes'; $placeholder = isset($field['placeholder']) ? $field['placeholder'] : ''; $label = $field['label']; $css_classes = array( 'wc-block-components-textarea', 'enspireplugins_acfw-field' ); if ($is_required) { $css_classes[] = 'is-required'; } echo '
'; echo ''; echo ''; echo '
'; } private function render_select_field($field) { $field_id = 'enspireplugins_acfw_' . $field['id']; $is_required = isset($field['required']) && $field['required'] === 'yes'; $label = $field['label']; $options = $this->process_field_options($field); $css_classes = array( 'wc-blocks-components-select', 'enspireplugins_acfw-field' ); if ($is_required) { $css_classes[] = 'is-required'; } echo '
'; echo '
'; echo ''; echo ''; echo ''; echo '
'; echo '
'; } private function render_checkbox_field($field) { $field_id = 'enspireplugins_acfw_' . $field['id']; $is_required = isset($field['required']) && $field['required'] === 'yes'; $label = $field['label']; echo '
'; echo ''; echo '
'; } private function render_radio_field($field) { $field_id = 'enspireplugins_acfw_' . $field['id']; $is_required = isset($field['required']) && $field['required'] === 'yes'; $label = $field['label']; $options = $this->process_field_options($field); if (empty($options)) { return; } echo '
'; $counter = 0; foreach ($options as $option_value => $option_label) { $radio_id = $field_id . '_' . $counter; echo ''; $counter++; } echo '
'; } public function render_fields_in_checkout() { if (!self::$block_rendered) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Already escaped in generate_checkout_fields_html echo $this->generate_checkout_fields_html(); self::$block_rendered = true; } } private function map_field_type_for_blocks($type) { $mapping = array( 'text' => 'text', 'textarea' => 'textarea', 'email' => 'email', 'url' => 'url', 'number' => 'number', 'select' => 'select', 'radio' => 'radio', 'checkbox' => 'checkbox', ); return isset($mapping[$type]) ? $mapping[$type] : 'text'; } public function save_block_fields_from_request($order, $request) { $request_data = $request->get_params(); $data_source = array(); // Retrieve and sanitize session data $session_data = array(); if (!session_id()) { session_start(); } if (isset($_SESSION['enspireplugins_acfw_checkout_data']) && is_array($_SESSION['enspireplugins_acfw_checkout_data'])) { $session_data = array_map('sanitize_text_field', wp_unslash($_SESSION['enspireplugins_acfw_checkout_data'])); unset($_SESSION['enspireplugins_acfw_checkout_data']); } foreach ($this->custom_fields as $field) { if (isset($field['active']) && $field['active'] === 'yes' && $field['type'] !== 'heading') { $field_id = 'enspireplugins_acfw_' . $field['id']; if (isset($session_data[$field_id])) { $data_source[$field_id] = $session_data[$field_id]; } elseif (isset($request_data['extensions']['enspireplugins-acfw'][$field_id])) { $data_source[$field_id] = $request_data['extensions']['enspireplugins-acfw'][$field_id]; } elseif (isset($request_data['billing_address'][$field_id])) { $data_source[$field_id] = $request_data['billing_address'][$field_id]; } elseif (isset($request_data['shipping_address'][$field_id])) { $data_source[$field_id] = $request_data['shipping_address'][$field_id]; } elseif (isset($_POST[$field_id])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified by WooCommerce Store API $data_source[$field_id] = sanitize_text_field(wp_unslash($_POST[$field_id])); // phpcs:ignore WordPress.Security.NonceVerification.Missing } } } if (!empty($data_source)) { $this->save_fields_to_order($order, $data_source); } } public function save_block_fields($order_id, $posted_data = array()) { if (!isset($_POST['woocommerce-process-checkout-nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['woocommerce-process-checkout-nonce'])), 'woocommerce-process_checkout')) { return; } $order = wc_get_order($order_id); if (!$order) { return; } $this->save_fields_to_order($order, 'POST'); } public function save_fields_on_order_processed($order_id, $posted_data, $order) { $this->save_fields_from_session($order); } public function save_fields_on_new_order($order_id) { $order = wc_get_order($order_id); if ($order) { $this->save_fields_from_session($order); } } private function save_fields_from_session($order) { if (!session_id()) { session_start(); } if (isset($_SESSION['enspireplugins_acfw_checkout_data']) && is_array($_SESSION['enspireplugins_acfw_checkout_data'])) { // Sanitize session data $session_data = array_map('sanitize_text_field', wp_unslash($_SESSION['enspireplugins_acfw_checkout_data'])); if (!empty($session_data)) { $this->save_fields_to_order($order, $session_data); unset($_SESSION['enspireplugins_acfw_checkout_data']); } } } public function get_store_api_data() { $active_fields = $this->get_active_fields(); $fields_data = $this->get_active_fields_for_editor(); $data = array( 'custom_fields_enabled' => !empty($active_fields), 'fields_count' => count($active_fields), 'fields_data' => $fields_data, 'plugin_version' => defined('ENSPIREPLUGINS_ACFW_VERSION') ? ENSPIREPLUGINS_ACFW_VERSION : '1.0.0', 'nonce' => wp_create_nonce('enspireplugins_acfw_checkout'), ); return $data; } public function get_store_api_schema() { return array( 'custom_fields_enabled' => array( 'description' => 'Whether custom checkout fields are enabled', 'type' => 'boolean', 'readonly' => true, ), 'fields_count' => array( 'description' => 'Number of active custom fields', 'type' => 'integer', 'readonly' => true, ), 'fields_data' => array( 'description' => 'Custom checkout fields configuration', 'type' => 'array', 'readonly' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'id' => array( 'type' => 'string', 'readonly' => true, ), 'label' => array( 'type' => 'string', 'readonly' => true, ), 'type' => array( 'type' => 'string', 'readonly' => true, 'enum' => array('text', 'textarea', 'number', 'email', 'url', 'select', 'radio', 'checkbox', 'heading'), ), 'required' => array( 'type' => 'boolean', 'readonly' => true, ), 'placeholder' => array( 'type' => 'string', 'readonly' => true, ), 'options' => array( 'type' => array('array', 'string'), 'readonly' => true, ), ), ), ), 'plugin_version' => array( 'description' => 'Plugin version', 'type' => 'string', 'readonly' => true, ), 'nonce' => array( 'description' => 'Security nonce', 'type' => 'string', 'readonly' => true, ), ); } public function ajax_save_checkout_data() { if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'enspireplugins_acfw_checkout')) { wp_die('Security check failed'); } $field_data = isset($_POST['field_data']) ? json_decode(sanitize_text_field(wp_unslash($_POST['field_data'])), true) : array(); if (!session_id()) { session_start(); } $_SESSION['enspireplugins_acfw_checkout_data'] = $field_data; wp_send_json_success(array('message' => 'Data saved to session')); } }