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_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 '
';
}
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'));
}
}