<?php

/**
 * Admin section.
 *
 * @package    Extra_Product_Options_For_WooCommerce
 * @subpackage Extra_Product_Options_For_WooCommerce/includes
 */
// If this file is called directly, abort.
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * EPOFW_Admin class.
 */
if ( !class_exists( 'EPOFW_Admin' ) ) {
    /**
     * EPOFW_Admin class.
     */
    class EPOFW_Admin {
        /**
         * The object of class.
         *
         * @since    1.0.0
         * @var      string $instance instance object.
         */
        protected static $instance = null;

        /**
         * The name of this plugin.
         *
         * @since    1.0.0
         * @var      string $plugin_name The ID of this plugin.
         */
        private $plugin_name;

        /**
         * The version of this plugin.
         *
         * @since    1.0.0
         * @var      string $version The current version of this plugin.
         */
        private $version;

        /**
         * Get current page.
         *
         * @var $page string Store current page.
         *
         * @since 1.0.0
         */
        private $page;

        /**
         * Get current tab.
         *
         * @var $current_tab string Store current tab.
         *
         * @since 1.0.0
         */
        private $current_tab;

        /**
         * Constructor.
         *
         * @since 1.0.0
         */
        public function __construct() {
            $this->plugin_name = EPOFW_PLUGIN_NAME;
            $this->version = EPOFW_PLUGIN_VERSION;
            require_once EPOFW_PLUGIN_DIR . '/includes/class-epofw-field-setting.php';
            $this->epofw_init();
        }

        /**
         * Define the plugins name and versions and also call admin section.
         *
         * @since 1.0.0
         */
        public static function instance() {
            if ( is_null( self::$instance ) ) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        /**
         * Register actions and filters.
         *
         * @since 1.0.0
         */
        public function epofw_init() {
            $prefix = ( is_network_admin() ? 'network_admin_' : '' );
            add_action( 'admin_menu', array($this, 'epofw_menu'), 99 );
            add_action( 'init', array($this, 'epofw_post_type') );
            add_action( 'admin_enqueue_scripts', array($this, 'epofw_enqueue_scripts_fn') );
            add_filter( 'epofw_getting_page', array($this, 'epofw_getting_page_fn'), 10 );
            add_filter( 'epofw_ie_admin_tab_ft', array($this, 'epofw_admin_tab'), 10 );
            add_filter( "{$prefix}plugin_action_links_" . plugin_basename( __FILE__ ), array($this, 'epofw_plugin_action_links'), 10 );
            add_action( 'wp_ajax_epofw_get_data_based_on_cd', array($this, 'epofw_get_data_based_on_cd') );
            add_action( 'wp_ajax_epofw_select_all_product', array($this, 'epofw_select_all_product') );
            add_action( 'wp_ajax_epofw_disbale_field_options', array($this, 'epofw_disbale_field_options') );
            add_action( 'admin_init', array($this, 'epofw_handle_existing_installations') );
            add_action( 'admin_notices', array($this, 'epofw_admin_review_notice') );
            add_action( 'wp_ajax_epofw_dismiss_review_notice', array($this, 'epofw_dismiss_review_notice') );
            add_action( 'wp_ajax_epofw_toggle_status_on_list', array($this, 'epofw_toggle_status_on_list') );
            add_action( 'wp_ajax_epofw_element_add', array($this, 'epofw_get_element_add_form') );
            add_action( 'wp_ajax_epofw_get_section_settings', array($this, 'epofw_get_section_settings_form') );
            add_action( 'wp_ajax_epofw_get_row_settings', array($this, 'epofw_get_row_settings_form') );
            add_action( 'wp_ajax_epofw_get_column_settings', array($this, 'epofw_get_column_settings_form') );
            add_action( 'wp_ajax_epofw_delete_addon', array($this, 'epofw_delete_addon') );
            add_action( 'wp_ajax_epofw_duplicate_addon', array($this, 'epofw_duplicate_addon') );
            add_action( 'wp_ajax_epofw_export_addon', array($this, 'epofw_export_addon') );
            // AJAX save handler (bypasses max_input_vars limit).
            add_action( 'wp_ajax_epofw_ajax_save_addon', array($this, 'epofw_ajax_save_addon') );
            // View preference handlers.
            add_action( 'wp_ajax_epofw_save_view_preference', array($this, 'epofw_save_view_preference') );
            add_action( 'wp_ajax_epofw_get_view_preference', array($this, 'epofw_get_view_preference') );
            // Search addons handler.
            add_action( 'wp_ajax_epofw_search_addons', array($this, 'epofw_search_addons') );
            // Migration handler.
            add_action( 'wp_ajax_epofw_migrate_to_sections', array($this, 'epofw_migrate_to_sections') );
        }

        /**
         * Post type register
         *
         * @since 1.0.0
         */
        public function epofw_post_type() {
            register_post_type( EPOFW_DFT_POST_TYPE, array(
                'labels' => array(
                    'name'          => esc_html__( 'Extra Product Option', 'extra-product-options-for-woocommerce' ),
                    'singular_name' => esc_html__( 'Extra Product Option', 'extra-product-options-for-woocommerce' ),
                ),
            ) );
        }

        /**
         * Where condition for WP_Query.
         *
         * @since    1.0.0
         *
         * @param mixed $where    Where condition for WP_Query.
         * @param mixed $wp_query WP_Query - For getting posts data.
         *
         * @return mixed $where Where condition for WP_Query.
         */
        public function epofw_posts_where( $where, $wp_query ) {
            global $wpdb;
            $search_term = $wp_query->get( 'search_pro_title' );
            if ( !empty( $search_term ) ) {
                $search_term_like = $wpdb->esc_like( $search_term );
                $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( $search_term_like ) . '%\'';
            }
            return $where;
        }

        /**
         * Select all products
         *
         * @since    1.0.0
         */
        public function epofw_select_all_product() {
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_select_all_product' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $request_data_cnd = ( isset( $_POST['data_cnd'] ) ? sanitize_text_field( wp_unslash( $_POST['data_cnd'] ) ) : '' );
            $data_array = array();
            if ( 'product' === $request_data_cnd ) {
                /**
                 * Filter the maximum number of products to retrieve in select all products dropdown.
                 *
                 * @since 4.4.4
                 * @param int $limit Maximum number of products. Default 500.
                 */
                $max_products = apply_filters( 'epofw_max_products_in_dropdown', 500 );
                $args = array(
                    'post_type'      => 'product',
                    'post_status'    => 'publish',
                    'posts_per_page' => $max_products,
                    'fields'         => 'ids',
                    'orderby'        => 'title',
                    'order'          => 'ASC',
                );
                $prd_query = new WP_Query($args);
                if ( !empty( $prd_query ) ) {
                    foreach ( $prd_query->posts as $prd_id ) {
                        $data_array[] = array($prd_id, get_the_title( $prd_id ));
                    }
                }
            } elseif ( 'category' === $request_data_cnd ) {
                $args = array(
                    'taxonomy'   => 'product_cat',
                    'orderby'    => 'name',
                    'hide_empty' => '',
                );
                $product_categories = get_terms( $args );
                if ( !empty( $product_categories ) ) {
                    foreach ( $product_categories as $product_categories_data ) {
                        $data_array[] = array($product_categories_data->term_id, $product_categories_data->name);
                    }
                }
            } elseif ( 'tag' === $request_data_cnd ) {
                $args = array(
                    'taxonomy'   => 'product_tag',
                    'orderby'    => 'name',
                    'hide_empty' => '',
                );
                $product_tags = get_terms( $args );
                if ( !empty( $product_tags ) ) {
                    foreach ( $product_tags as $product_tag_data ) {
                        $data_array[] = array($product_tag_data->term_id, $product_tag_data->name);
                    }
                }
            }
            echo wp_json_encode( $data_array );
            wp_die();
        }

        /**
         * Get data based on conditional rule with pagination support.
         *
         * @since    1.0.0
         * @since    4.4.4 Added pagination support for Select2 infinite scroll.
         */
        public function epofw_get_data_based_on_cd() {
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'You have not permission for this one.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $get_data_based_on_cd_nonce = filter_input( INPUT_POST, 'get_data_based_on_cd_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( empty( $get_data_based_on_cd_nonce ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $get_data_based_on_cd_nonce = sanitize_text_field( wp_unslash( $get_data_based_on_cd_nonce ) );
            if ( !wp_verify_nonce( $get_data_based_on_cd_nonce, 'epofw_get_data_based_on_cd_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $request_value = filter_input( INPUT_POST, 'value', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            $post_value = ( isset( $request_value ) ? sanitize_text_field( wp_unslash( epofw_get_cyric_string_to_latin( $request_value ) ) ) : '' );
            $current_condition = filter_input( INPUT_POST, 'current_condition', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            $current_val = ( isset( $current_condition ) ? sanitize_text_field( wp_unslash( $current_condition ) ) : 'product' );
            // Pagination parameters for Select2 infinite scroll.
            $page = ( isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1 );
            $per_page = ( isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 50 );
            // Ensure per_page is within reasonable limits.
            $per_page = min( max( $per_page, 10 ), 100 );
            $data_array = array();
            $total_count = 0;
            $has_more = false;
            if ( 'product' === $current_val ) {
                $offset = ($page - 1) * $per_page;
                $args = array(
                    'post_type'      => 'product',
                    'post_status'    => 'publish',
                    'posts_per_page' => $per_page,
                    'offset'         => $offset,
                    'fields'         => 'ids',
                    'orderby'        => 'title',
                    'order'          => 'ASC',
                );
                if ( !empty( $post_value ) ) {
                    $args['search_pro_title'] = $post_value;
                    add_filter(
                        'posts_where',
                        array($this, 'epofw_posts_where'),
                        10,
                        2
                    );
                    $prd_query = new WP_Query($args);
                    remove_filter(
                        'posts_where',
                        array($this, 'epofw_posts_where'),
                        10,
                        2
                    );
                } else {
                    $prd_query = new WP_Query($args);
                }
                $total_count = $prd_query->found_posts;
                $has_more = $offset + $per_page < $total_count;
                if ( !empty( $prd_query->posts ) ) {
                    foreach ( $prd_query->posts as $prd_id ) {
                        $data_array[] = array($prd_id, get_the_title( $prd_id ));
                    }
                }
            } elseif ( 'category' === $current_val ) {
                $offset = ($page - 1) * $per_page;
                $args = array(
                    'taxonomy'   => 'product_cat',
                    'orderby'    => 'name',
                    'hide_empty' => false,
                    'number'     => $per_page,
                    'offset'     => $offset,
                );
                if ( !empty( $post_value ) ) {
                    $args['search'] = $post_value;
                }
                $product_categories = get_terms( $args );
                // Get total count.
                $count_args = array(
                    'taxonomy'   => 'product_cat',
                    'hide_empty' => false,
                    'fields'     => 'count',
                );
                if ( !empty( $post_value ) ) {
                    $count_args['search'] = $post_value;
                }
                $total_count = (int) get_terms( $count_args );
                $has_more = $offset + $per_page < $total_count;
                if ( !empty( $product_categories ) && !is_wp_error( $product_categories ) ) {
                    foreach ( $product_categories as $product_categories_data ) {
                        $data_array[] = array($product_categories_data->term_id, $product_categories_data->name);
                    }
                }
            } elseif ( 'tag' === $current_val ) {
                $offset = ($page - 1) * $per_page;
                $args = array(
                    'taxonomy'   => 'product_tag',
                    'orderby'    => 'name',
                    'hide_empty' => false,
                    'number'     => $per_page,
                    'offset'     => $offset,
                );
                if ( !empty( $post_value ) ) {
                    $args['search'] = $post_value;
                }
                $product_tags = get_terms( $args );
                // Get total count.
                $count_args = array(
                    'taxonomy'   => 'product_tag',
                    'hide_empty' => false,
                    'fields'     => 'count',
                );
                if ( !empty( $post_value ) ) {
                    $count_args['search'] = $post_value;
                }
                $total_count = (int) get_terms( $count_args );
                $has_more = $offset + $per_page < $total_count;
                if ( !empty( $product_tags ) && !is_wp_error( $product_tags ) ) {
                    foreach ( $product_tags as $product_tag_data ) {
                        $data_array[] = array($product_tag_data->term_id, $product_tag_data->name);
                    }
                }
            }
            // Return response in Select2 pagination format.
            $response = array(
                'results'    => $data_array,
                'pagination' => array(
                    'more' => $has_more,
                ),
                'total'      => $total_count,
            );
            echo wp_json_encode( $response );
            wp_die();
        }

        /**
         * Using tab array.
         *
         * @return array $tab_array
         *
         * @since 1.0.0
         */
        public static function epofw_admin_action_tab_fn() {
            $current_tab_array = array(
                'epofw_gs'      => esc_html__( 'General Settings', 'extra-product-options-for-woocommerce' ),
                'epofw_global'  => esc_html__( 'Global Settings', 'extra-product-options-for-woocommerce' ),
                'field-section' => esc_html__( 'Product Option', 'extra-product-options-for-woocommerce' ),
                'about_info'    => esc_html__( 'Documentation', 'extra-product-options-for-woocommerce' ),
            );
            return $current_tab_array;
        }

        /**
         * Getting Tab array.
         *
         * @param array $aon_tab_array Checking array tab.
         *
         * @return array $tab_array Checking array tab.
         *
         * @since 1.0.0
         */
        public function epofw_admin_tab( $aon_tab_array ) {
            $current_tab_array = self::epofw_admin_action_tab_fn();
            if ( !empty( $aon_tab_array ) ) {
                $tab_array = array_merge( $current_tab_array, $aon_tab_array );
            } else {
                $tab_array = $current_tab_array;
            }
            return $tab_array;
        }

        /**
         * Add menu in woocommerce main menu.
         *
         * @since 1.0.0
         */
        public function epofw_menu() {
            add_submenu_page(
                'woocommerce',
                'Extra Product Addons',
                'Extra Product Addons',
                'manage_options',
                'epofw-main',
                array($this, 'epofw_main_fn'),
                70
            );
        }

        /**
         * Enqueue plugins css and js for admin purpose.
         *
         * @param string $hook pages main name.
         *
         * @since 1.0.0
         */
        public function epofw_enqueue_scripts_fn( $hook ) {
            if ( false !== strpos( $hook, 'epofw-main' ) ) {
                $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' );
                $pro_path = '';
                $get_post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT );
                $get_post_id = ( isset( $get_post_id ) ? sanitize_text_field( wp_unslash( $get_post_id ) ) : '' );
                wp_enqueue_style(
                    'epofw-admin-css',
                    EPOFW_PLUGIN_URL . 'assets/' . $pro_path . 'css/epofw-product-addons.css',
                    array(),
                    $this->version
                );
                // Add inline styles for import modal.
                $import_modal_css = '
					.epofw-import-modal-overlay {
						position: fixed;
						top: 0;
						left: 0;
						width: 100%;
						height: 100%;
						background: rgba(0, 0, 0, 0.7);
						z-index: 100000;
						display: none;
						align-items: center;
						justify-content: center;
					}
					.epofw-import-modal-content {
						background: #fff;
						border-radius: 8px;
						max-width: 500px;
						width: 90%;
						box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
						animation: epofwSlideDown 0.3s ease-out;
					}
					@keyframes epofwSlideDown {
						from {
							opacity: 0;
							transform: translateY(-50px);
						}
						to {
							opacity: 1;
							transform: translateY(0);
						}
					}
					.epofw-import-modal-header {
						padding: 20px 24px;
						border-bottom: 1px solid #e5e7eb;
						display: flex;
						justify-content: space-between;
						align-items: center;
					}
					.epofw-import-modal-header h3 {
						margin: 0;
						font-size: 18px;
						font-weight: 600;
						color: #1f2937;
					}
					.epofw-import-modal-close {
						background: none;
						border: none;
						font-size: 28px;
						line-height: 1;
						color: #9ca3af;
						cursor: pointer;
						padding: 0;
						width: 30px;
						height: 30px;
						display: flex;
						align-items: center;
						justify-content: center;
						border-radius: 4px;
						transition: all 0.2s;
					}
					.epofw-import-modal-close:hover {
						background: #f3f4f6;
						color: #374151;
					}
					.epofw-import-modal-body {
						padding: 24px;
					}
					.epofw-import-modal-body p {
						margin: 0 0 16px;
						color: #6b7280;
						font-size: 14px;
						line-height: 1.6;
					}
					.epofw-import-modal-body p:last-child {
						margin-bottom: 0;
					}
					.epofw-import-modal-footer {
						padding: 16px 24px;
						border-top: 1px solid #e5e7eb;
						display: flex;
						justify-content: flex-end;
						gap: 12px;
					}
					.epofw-import-loading {
						text-align: center;
						padding: 20px 0;
					}
					.epofw-spinner {
						border: 3px solid #f3f4f6;
						border-top: 3px solid #3b82f6;
						border-radius: 50%;
						width: 40px;
						height: 40px;
						animation: epofwSpin 1s linear infinite;
						margin: 0 auto 16px;
					}
					@keyframes epofwSpin {
						0% { transform: rotate(0deg); }
						100% { transform: rotate(360deg); }
					}
					.epofw-import-loading p {
						color: #6b7280;
						font-size: 14px;
					}
					.epofw-import-success {
						text-align: center;
						padding: 20px 0;
					}
					.epofw-import-success i {
						font-size: 48px;
						color: #10b981;
						margin-bottom: 16px;
					}
					.epofw-import-success p {
						color: #059669;
						font-size: 16px;
						font-weight: 500;
						margin: 0;
					}
					.epofw-import-error {
						text-align: center;
						padding: 20px 0;
					}
					.epofw-import-error i {
						font-size: 48px;
						color: #ef4444;
						margin-bottom: 16px;
					}
					.epofw-import-error p {
						color: #dc2626;
						font-size: 16px;
						font-weight: 500;
						margin: 0;
					}
				';
                wp_add_inline_style( 'epofw-admin-css', $import_modal_css );
                wp_enqueue_style(
                    'select2-min-css',
                    EPOFW_PLUGIN_URL . 'assets/css/select2.min.css',
                    array(),
                    'all'
                );
                wp_enqueue_script(
                    'select2-min-js',
                    EPOFW_PLUGIN_URL . 'assets/js/select2.full.min.js',
                    array('jquery'),
                    $this->version,
                    true
                );
                wp_enqueue_script(
                    'epofw-toast-js',
                    EPOFW_PLUGIN_URL . 'lib/toast/toastr.min.js',
                    array('jquery'),
                    $this->version,
                    true
                );
                wp_enqueue_style(
                    'epofw-toast-css',
                    EPOFW_PLUGIN_URL . 'lib/toast/toastr.min.css',
                    array(),
                    $this->version
                );
                wp_enqueue_script( 'jquery-ui-sortable' );
                wp_enqueue_script( 'jquery-ui-datepicker' );
                wp_enqueue_script(
                    'jquery-ui-timepicker-js',
                    EPOFW_PLUGIN_URL . 'assets/js/jquery-ui-timepicker.js',
                    array('jquery-ui-datepicker'),
                    $this->version,
                    true
                );
                wp_enqueue_style(
                    'jquery-ui-timepicker-css',
                    EPOFW_PLUGIN_URL . 'assets/css/jquery-ui-timepicker.css',
                    array(),
                    'all'
                );
                wp_enqueue_style( 'wp-color-picker' );
                wp_enqueue_script( 'wp-color-picker' );
                wp_enqueue_style(
                    'jquery-ui-css',
                    EPOFW_PLUGIN_URL . 'assets/css/jquery-ui.min.css',
                    '',
                    '1.0.0'
                );
                wp_enqueue_script(
                    'epofw-admin-js',
                    EPOFW_PLUGIN_URL . 'assets/' . $pro_path . 'js/epofw-admin' . $suffix . '.js',
                    array(
                        'jquery',
                        'jquery-tiptip',
                        'jquery-ui-datepicker',
                        'wp-util'
                    ),
                    $this->version,
                    true
                );
                $localize_args = array(
                    'ajaxurl'                     => admin_url( 'admin-ajax.php' ),
                    'admin_url'                   => admin_url(),
                    'get_post_id'                 => $get_post_id,
                    'condition_options'           => epofw_field_additional_conditional_name(),
                    'operator_options'            => epofw_field_additional_conditional_operator(),
                    'get_data_based_on_cd_nonce'  => wp_create_nonce( 'epofw_get_data_based_on_cd_nonce' ),
                    'disable_option_nonce'        => wp_create_nonce( 'epofw_disable_option_nonce' ),
                    'delete_addon_nonce'          => wp_create_nonce( 'epofw_delete_addon_nonce' ),
                    'duplicate_addon_nonce'       => wp_create_nonce( 'epofw_duplicate_addon_nonce' ),
                    'change_field_nonce'          => wp_create_nonce( 'epofw_change_field_nonce' ),
                    'dismiss_review_notice_nonce' => wp_create_nonce( 'epofw_dismiss_review_notice_nonce' ),
                    'toggle_status_nonce'         => wp_create_nonce( 'epofw_toggle_status_nonce' ),
                    'element_add_nonce'           => wp_create_nonce( 'epofw_element_add_nonce' ),
                    'import_fields_nonce'         => wp_create_nonce( 'epofw_import_fields_nonce' ),
                    'ajax_save_nonce'             => wp_create_nonce( 'epofw_ajax_save_addon' ),
                    'select_all_nonce'            => wp_create_nonce( 'epofw_select_all_product' ),
                    'settings'                    => esc_html__( 'Settings', 'extra-product-options-for-woocommerce' ),
                    'section_name'                => esc_html__( 'Section', 'extra-product-options-for-woocommerce' ),
                    'fields_icon_description'     => epofw_get_field_type_with_icon_and_description(),
                    'nonce'                       => wp_create_nonce( 'epofw_migration_nonce' ),
                    'epofw_admin_nonce'           => wp_create_nonce( 'epofw_admin_nonce' ),
                    'strings'                     => array(
                        'migrating'                  => esc_html__( 'Migrating addons to sections...', 'extra-product-options-for-woocommerce' ),
                        'success'                    => esc_html__( 'Migration completed successfully!', 'extra-product-options-for-woocommerce' ),
                        'error'                      => esc_html__( 'Migration failed. Please try again.', 'extra-product-options-for-woocommerce' ),
                        'created'                    => esc_html__( 'Product Field successfully created.', 'extra-product-options-for-woocommerce' ),
                        'saved'                      => esc_html__( 'Product Field successfully updated.', 'extra-product-options-for-woocommerce' ),
                        'deleted'                    => esc_html__( 'Product Field deleted.', 'extra-product-options-for-woocommerce' ),
                        'duplicated'                 => esc_html__( 'Product Field duplicated.', 'extra-product-options-for-woocommerce' ),
                        'disabled'                   => esc_html__( 'Product Field disabled.', 'extra-product-options-for-woocommerce' ),
                        'enabled'                    => esc_html__( 'Product Field enabled.', 'extra-product-options-for-woocommerce' ),
                        'imported'                   => esc_html__( 'Fields imported successfully.', 'extra-product-options-for-woocommerce' ),
                        'failed'                     => esc_html__( 'There was an error with saving data.', 'extra-product-options-for-woocommerce' ),
                        'nonce_check'                => esc_html__( 'There was an error with security check.', 'extra-product-options-for-woocommerce' ),
                        'validated'                  => esc_html__( 'There was an error with validation.', 'extra-product-options-for-woocommerce' ),
                        'settings_saved'             => esc_html__( 'Settings save successfully', 'extra-product-options-for-woocommerce' ),
                        'delete_addon_confirm'       => esc_html__( 'Are you sure you want to delete this addon?', 'extra-product-options-for-woocommerce' ),
                        'delete_addon_field'         => esc_html__( 'Are you sure you want to delete this field?', 'extra-product-options-for-woocommerce' ),
                        'duplicate_addon_confirm'    => esc_html__( 'Are you sure you want to duplicate this addon?', 'extra-product-options-for-woocommerce' ),
                        'import_confirm'             => esc_html__( 'Are you sure you want to import demo fields? This will create a new addon with sample fields.', 'extra-product-options-for-woocommerce' ),
                        'import_confirm_title'       => esc_html__( 'Import Demo Fields', 'extra-product-options-for-woocommerce' ),
                        'import_confirm_message'     => esc_html__( 'This will create a new demo addon with sample fields. Do you want to continue?', 'extra-product-options-for-woocommerce' ),
                        'cancel'                     => esc_html__( 'Cancel', 'extra-product-options-for-woocommerce' ),
                        'import_now'                 => esc_html__( 'Import Now', 'extra-product-options-for-woocommerce' ),
                        'importing'                  => esc_html__( 'Importing demo fields, please wait...', 'extra-product-options-for-woocommerce' ),
                        'import_error'               => esc_html__( 'An error occurred while importing. Please try again.', 'extra-product-options-for-woocommerce' ),
                        'limit_addon_message'        => esc_html__( 'You can not add more than one field in the same row.', 'extra-product-options-for-woocommerce' ),
                        'validation_error_title'     => esc_html__( 'Validation Error', 'extra-product-options-for-woocommerce' ),
                        'required_fields_missing'    => esc_html__( 'Please fill in the following required fields before saving:', 'extra-product-options-for-woocommerce' ),
                        'deleting'                   => esc_html__( 'Deleting...', 'extra-product-options-for-woocommerce' ),
                        'duplicating'                => esc_html__( 'Duplicating...', 'extra-product-options-for-woocommerce' ),
                        'updating'                   => esc_html__( 'Updating...', 'extra-product-options-for-woocommerce' ),
                        'loading_settings'           => esc_html__( 'Loading settings...', 'extra-product-options-for-woocommerce' ),
                        'loading'                    => esc_html__( 'Loading...', 'extra-product-options-for-woocommerce' ),
                        'saving'                     => esc_html__( 'Saving...', 'extra-product-options-for-woocommerce' ),
                        'saving_addon'               => esc_html__( 'Saving addon...', 'extra-product-options-for-woocommerce' ),
                        'save_failed'                => esc_html__( 'Save failed:', 'extra-product-options-for-woocommerce' ),
                        'save_error'                 => esc_html__( 'An error occurred while saving.', 'extra-product-options-for-woocommerce' ),
                        'duplicate_error'            => esc_html__( 'An error occurred while duplicating the addon.', 'extra-product-options-for-woocommerce' ),
                        'export_error'               => esc_html__( 'An error occurred while exporting the addon.', 'extra-product-options-for-woocommerce' ),
                        'delete_column_confirm'      => esc_html__( 'Are you sure you want to delete this column and all its elements?', 'extra-product-options-for-woocommerce' ),
                        'delete_row_confirm'         => esc_html__( 'Are you sure you want to delete this row and all its columns?', 'extra-product-options-for-woocommerce' ),
                        'export_success'             => esc_html__( 'Addon exported successfully!', 'extra-product-options-for-woocommerce' ),
                        'export_failed'              => esc_html__( 'Export failed.', 'extra-product-options-for-woocommerce' ),
                        'addon_id_not_found'         => esc_html__( 'Addon ID not found.', 'extra-product-options-for-woocommerce' ),
                        'delete_columns_confirm'     => esc_html__( 'Are you sure you want to delete this columns group?', 'extra-product-options-for-woocommerce' ),
                        'delete_columns_with_fields' => esc_html__( 'Are you sure you want to delete this columns group and all %d field(s) inside it?', 'extra-product-options-for-woocommerce' ),
                        'columns_deleted'            => esc_html__( 'Columns deleted', 'extra-product-options-for-woocommerce' ),
                        'import_demo_addons'         => esc_html__( 'Import Demo Addons', 'extra-product-options-for-woocommerce' ),
                        'this_will_import'           => esc_html__( 'This will import:', 'extra-product-options-for-woocommerce' ),
                        'demo_tshirt'                => esc_html__( 'T-Shirt Customization Demo', 'extra-product-options-for-woocommerce' ),
                        'demo_pizza'                 => esc_html__( 'Pizza Order Demo', 'extra-product-options-for-woocommerce' ),
                        'demo_event'                 => esc_html__( 'Event Registration Demo', 'extra-product-options-for-woocommerce' ),
                        'demo_premium'               => esc_html__( 'Premium Features Showcase', 'extra-product-options-for-woocommerce' ),
                        'view_more'                  => esc_html__( 'View more', 'extra-product-options-for-woocommerce' ),
                        'view_less'                  => esc_html__( 'View less', 'extra-product-options-for-woocommerce' ),
                    ),
                );
                $localize_args['is_premium'] = false;
                // Add premium field types and upgrade URL for free users.
                $localize_args['premium_field_types'] = epofw_get_premium_field_types();
                $localize_args['upgrade_url'] = epofw_fs()->get_upgrade_url();
                $localize_args['pro_label'] = esc_html__( 'PRO', 'extra-product-options-for-woocommerce' );
                $localize_args['upgrade_to_pro'] = esc_html__( 'Upgrade to Pro', 'extra-product-options-for-woocommerce' );
                $localize_args['premium_feature_title'] = esc_html__( 'Premium Feature', 'extra-product-options-for-woocommerce' );
                $localize_args['premium_feature_msg'] = esc_html__( 'This field type is available in the Pro version. Upgrade now to unlock all premium features!', 'extra-product-options-for-woocommerce' );
                $localize_args['cancel_text'] = esc_html__( 'Cancel', 'extra-product-options-for-woocommerce' );
                $localize_args['discount_offer_text'] = esc_html__( 'Save 50% - Limited Time Offer!', 'extra-product-options-for-woocommerce' );
                /**
                 * Filter admin localized script data.
                 *
                 * Allows modules to add custom data to the epofw_var JavaScript object.
                 *
                 * @since 4.4.5
                 *
                 * @param array $localize_args Array of data to be localized.
                 */
                $localize_args = apply_filters( 'epofw_admin_localize_data', $localize_args );
                wp_localize_script( 'epofw-admin-js', 'epofw_var', $localize_args );
                // Enqueue migration script.
                wp_enqueue_script(
                    'epofw-migration-js',
                    EPOFW_PLUGIN_URL . 'assets/' . $pro_path . 'js/epofw-migration' . $suffix . '.js',
                    array('jquery'),
                    $this->version,
                    true
                );
                wp_localize_script( 'epofw-migration-js', 'epofw_migration_vars', array(
                    'ajaxurl' => admin_url( 'admin-ajax.php' ),
                    'nonce'   => wp_create_nonce( 'epofw_migrate_to_sections_nonce' ),
                    'strings' => array(
                        'migrating' => esc_html__( 'Migrating addons...', 'extra-product-options-for-woocommerce' ),
                        'success'   => esc_html__( 'Migration completed successfully!', 'extra-product-options-for-woocommerce' ),
                        'error'     => esc_html__( 'Migration failed. Please try again.', 'extra-product-options-for-woocommerce' ),
                    ),
                ) );
                // Enqueue admin filter script for addon list search/filter.
                wp_enqueue_script(
                    'epofw-admin-filter-js',
                    EPOFW_PLUGIN_URL . 'assets/js/epofw-admin-filter.js',
                    array('jquery'),
                    $this->version,
                    true
                );
                /**
                 * Fires after admin scripts and styles are enqueued.
                 *
                 * Allows modules to enqueue their own admin scripts and styles.
                 *
                 * @since 4.4.5
                 *
                 * @param string $hook The current admin page hook suffix.
                 */
                do_action( 'epofw_admin_enqueue_scripts', $hook );
            }
        }

        /**
         * Manage Field List Page.
         *
         * @since    1.0.0
         */
        public function epofw_main_fn() {
            $this->page = self::epofw_current_page();
            $this->current_tab = self::epofw_current_tab();
            /**
             * Action for current tab.
             *
             * @since 1.0.0
             */
            $current_tab_array = do_action( 'epofw_admin_action_current_tab' );
            if ( has_filter( 'epofw_ie_admin_tab_ft' ) ) {
                /**
                 * Apply filter for admin tab.
                 *
                 * @since 1.0.0
                 */
                $tabing_array = apply_filters( 'epofw_ie_admin_tab_ft', $current_tab_array );
            } else {
                /**
                 * Apply filter for admin tab.
                 *
                 * @since 1.0.0
                 */
                $tabing_array = apply_filters( 'epofw_admin_tab_ft', '' );
            }
            ?>
			<div class="wrap woocommerce">
				<h1><?php 
            echo esc_html( $this->plugin_name );
            ?></h1>
				<form method="post"
					enctype="multipart/form-data">
					<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
						<?php 
            if ( !empty( $tabing_array ) ) {
                foreach ( $tabing_array as $name => $label ) {
                    $url = self::dynamic_url( $this->page, $name );
                    echo '<a href="' . esc_url( $url ) . '" class="nav-tab ';
                    if ( $this->current_tab === $name ) {
                        echo 'nav-tab-active';
                    }
                    echo '">' . esc_html( $label ) . '</a>';
                }
            }
            ?>
					</nav>
					<?php 
            if ( has_filter( 'epofw_ie_admin_page_ft' ) ) {
                /**
                 * Apply filter for admin page.
                 *
                 * @since 1.0.0
                 */
                apply_filters( 'epofw_ie_admin_page_ft', $this->current_tab );
                /**
                 * Apply filter for getting page.
                 *
                 * @since 1.0.0
                 */
                apply_filters( 'epofw_getting_page', $this->current_tab );
            } else {
                /**
                 * Apply filter for getting page.
                 *
                 * @since 1.0.0
                 */
                apply_filters( 'epofw_getting_page', $this->current_tab );
            }
            ?>
				</form>
			</div>
			<?php 
        }

        /**
         * Getting dynamic url.
         *
         * @since 1.0.0
         *
         * @param string $page    Getting page name.
         * @param string $tab     Getting tab name.
         * @param string $action  Getting action.
         * @param string $post_id Getting current post id.
         * @param string $nonce   Checking nonce if available in url.
         * @param string $message Checking if any dynamic messages pass in url.
         *
         * @return string $url return url.
         */
        public static function dynamic_url(
            $page = '',
            $tab = '',
            $action = '',
            $post_id = '',
            $nonce = '',
            $message = ''
        ) {
            $url_args = array(
                'page' => $page,
            );
            if ( !empty( $tab ) ) {
                $url_args['tab'] = $tab;
            }
            if ( !empty( $action ) ) {
                $url_args['action'] = $action;
            }
            if ( !empty( $message ) ) {
                $url_args['msg'] = $message;
            }
            if ( !empty( $post_id ) ) {
                $url_args['post'] = $post_id;
            }
            if ( !empty( $nonce ) ) {
                $url_args['_wpnonce'] = $nonce;
            }
            return add_query_arg( $url_args, admin_url( 'admin.php' ) );
        }

        /**
         * Getting Page.
         *
         * @param string $current_tab Getting current tab name.
         *
         * @since 1.0.0
         */
        public function epofw_getting_page_fn( $current_tab ) {
            if ( 'field-section' === $current_tab ) {
                $epofw_sms = new EPOFW_Field_Setting();
                $epofw_sms->epofw_output();
            } elseif ( 'about_info' === $current_tab ) {
                include_once EPOFW_PLUGIN_DIR . '/settings/epofw-about-info.php';
            } elseif ( 'epofw_gs' === $current_tab ) {
                include_once EPOFW_PLUGIN_DIR . '/settings/epofw-general-settings.php';
            } elseif ( 'epofw_global' === $current_tab ) {
                include_once EPOFW_PLUGIN_DIR . '/settings/epofw-global-settings.php';
            }
        }

        /**
         * Get current page.
         *
         * @return string $current_page Getting current page name.
         *
         * @since 1.0.0
         */
        public static function epofw_current_page() {
            $current_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            return sanitize_text_field( wp_unslash( $current_page ) );
        }

        /**
         * Get current tab.
         *
         * @return string $current_tab Getting current tab name.
         *
         * @since 1.0.0
         */
        public static function epofw_current_tab() {
            $current_tab = filter_input( INPUT_GET, 'tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( !isset( $current_tab ) ) {
                $current_tab = 'field-section';
            }
            return sanitize_text_field( wp_unslash( $current_tab ) );
        }

        /**
         * Validate message for plugins form.
         *
         * @param string $message        Custom Validate message for plugins form.
         *
         * @param string $tab            Get current tab for current page.
         *
         * @param string $validation_msg Display validation error.
         *
         * @return bool
         *
         * @since 1.0.0
         */
        public static function epofw_updated_message( $message, $tab, $validation_msg ) {
            if ( empty( $message ) ) {
                return false;
            }
            if ( 'field-section' === $tab ) {
                if ( 'created' === $message ) {
                    $updated_message = esc_html__( 'Product Field successfully created.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'saved' === $message ) {
                    $updated_message = esc_html__( 'Product Field successfully updated.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'deleted' === $message ) {
                    $updated_message = esc_html__( 'Product Field deleted.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'duplicated' === $message ) {
                    $updated_message = esc_html__( 'Product Field duplicated.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'disabled' === $message ) {
                    $updated_message = esc_html__( 'Product Field disabled.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'enabled' === $message ) {
                    $updated_message = esc_html__( 'Product Field enabled.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'imported' === $message ) {
                    $updated_message = esc_html__( 'Fields imported successfully.', 'extra-product-options-for-woocommerce' );
                }
                if ( 'failed' === $message ) {
                    $failed_messsage = esc_html__( 'There was an error with saving data.', 'extra-product-options-for-woocommerce' );
                } elseif ( 'nonce_check' === $message ) {
                    $failed_messsage = esc_html__( 'There was an error with security check.', 'extra-product-options-for-woocommerce' );
                }
                if ( 'validated' === $message ) {
                    $validated_messsage = esc_html( $validation_msg );
                }
            } else {
                if ( 'saved' === $message ) {
                    $updated_message = esc_html__( 'Settings save successfully', 'extra-product-options-for-woocommerce' );
                }
                if ( 'nonce_check' === $message ) {
                    $failed_messsage = esc_html__( 'There was an error with security check.', 'extra-product-options-for-woocommerce' );
                }
                if ( 'validated' === $message ) {
                    $validated_messsage = esc_html( $validation_msg );
                }
            }
            if ( !empty( $updated_message ) ) {
                printf( '<div id="message" class="notice notice-success is-dismissible"><p>%s</p></div>', esc_html( $updated_message ) );
                return false;
            }
            if ( !empty( $failed_messsage ) ) {
                printf( '<div id="message" class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html( $failed_messsage ) );
                return false;
            }
            if ( !empty( $validated_messsage ) ) {
                printf( '<div id="message" class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html( $validated_messsage ) );
                return false;
            }
        }

        /**
         * Disable field options.
         *
         * @since 2.0
         */
        public function epofw_disbale_field_options() {
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'You have not permission for this one.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $disable_option_nonce = filter_input( INPUT_POST, 'disable_option_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( empty( $disable_option_nonce ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $disable_option_nonce = sanitize_text_field( wp_unslash( $disable_option_nonce ) );
            if ( !wp_verify_nonce( $disable_option_nonce, 'epofw_disable_option_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $get_post_id = filter_input( INPUT_POST, 'get_post_id', FILTER_SANITIZE_NUMBER_INT );
            $get_post_id = ( isset( $get_post_id ) ? sanitize_text_field( wp_unslash( $get_post_id ) ) : '' );
            $field_ids = filter_input(
                INPUT_POST,
                'field_ids',
                FILTER_SANITIZE_NUMBER_INT,
                FILTER_REQUIRE_ARRAY
            );
            $updated_data = false;
            if ( !empty( $get_post_id ) && !empty( $field_ids ) ) {
                $get_data = epofw_get_data_from_db( $get_post_id );
                if ( !empty( $get_data ) ) {
                    foreach ( $field_ids as $field_id ) {
                        if ( isset( $get_data['general'][$field_id]['field']['status'] ) && 'on' === $get_data['general'][$field_id]['field']['status'] || isset( $get_data['general'][$field_id]['field_status'] ) ) {
                            unset($get_data['general'][$field_id]['field']['status']);
                            unset($get_data['general'][$field_id]['field_status']);
                        } else {
                            $get_data['general'][$field_id]['field']['status'] = 'on';
                            $get_data['general'][$field_id]['field_status'] = 'on';
                        }
                    }
                }
                // Save to custom tables.
                $updated_data = epofw_save_data_to_db( $get_post_id, $get_data );
            }
            if ( $updated_data ) {
                wp_send_json_success();
            } else {
                wp_send_json_error();
            }
            wp_die();
        }

        /**
         * Display plugin image.
         *
         * @since 3.0.9
         *
         * @param string $image_name Image name.
         * @param string $alt Alt text.
         * @param string $class Class name.
         */
        public static function epofw_display_plugin_image( $image_name, $alt = '', $class = '' ) {
            $image_url = EPOFW_PLUGIN_URL . '/assets/images/' . $image_name;
            $image_path = EPOFW_PLUGIN_DIR . '/assets/images/' . $image_name;
            if ( file_exists( $image_path ) ) {
                printf(
                    '<img src="%s" alt="%s" class="%s" />',
                    esc_url( $image_url ),
                    esc_attr( $alt ),
                    esc_attr( $class )
                );
            }
        }

        /**
         * Function to handle existing installations.
         *
         * @since 4.2
         */
        public function epofw_handle_existing_installations() {
            // Check if install date already exists.
            $install_date = get_option( 'epofw_install_date' );
            if ( !$install_date ) {
                $install_date = time() - 2 * DAY_IN_SECONDS;
                add_option( 'epofw_install_date', $install_date );
            }
        }

        /**
         * Function to add review notice.
         *
         * @since 4.2
         */
        public function epofw_admin_review_notice() {
            // Only show to admins.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                return;
            }
            // Check if dismissed.
            $dismissed = get_user_meta( get_current_user_id(), 'epofw_review_notice_dismissed', true );
            if ( $dismissed ) {
                return;
            }
            // Check if we're on plugin page.
            $screen = get_current_screen();
            if ( !in_array( $screen->id, array('product_page_epofw-main', 'plugins'), true ) ) {
                return;
            }
            // Get installation time.
            $install_date = get_option( 'epofw_install_date', time() );
            $trigger_time = $install_date + 1 * DAY_IN_SECONDS;
            if ( time() < $trigger_time ) {
                return;
            }
            ?>
			<div class="notice notice-info is-dismissible epofw-review-notice">
				<p>
				<?php 
            printf( 
                /* translators: %1$s: Plugin name, %2$s: Link to review page */
                esc_html__( 'Hey! We noticed you\'ve been using %1$s for a while now - we hope you love it! Could you please do us a huge favor and give it a 5-star rating on WordPress? It would help us spread the word and boost our motivation. %2$s', 'extra-product-options-for-woocommerce' ),
                '<strong>Extra Product Options for WooCommerce</strong>',
                '<a href="https://wordpress.org/support/plugin/extra-product-options-for-woocommerce/reviews/#new-post" target="_blank">' . esc_html__( 'Click here to leave a review', 'extra-product-options-for-woocommerce' ) . '</a>'
             );
            ?>
				</p>
			</div>
			<?php 
        }

        /**
         * Dismiss the review notice.
         *
         * @since 4.2
         */
        public function epofw_dismiss_review_notice() {
            if ( !isset( $_POST['dismiss_review_notice_nonce'] ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Verify nonce dismissal.
            $get_nonce = sanitize_text_field( wp_unslash( $_POST['dismiss_review_notice_nonce'] ) );
            if ( empty( $get_nonce ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            if ( !wp_verify_nonce( $get_nonce, 'epofw_dismiss_review_notice_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            update_user_meta( get_current_user_id(), 'epofw_review_notice_dismissed', true );
            wp_die();
        }

        /**
         * Toggle status on list.
         *
         * @since 4.4.0
         */
        public function epofw_toggle_status_on_list() {
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'You have not permission for this one.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $toggle_status_nonce = filter_input( INPUT_POST, 'toggle_status_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
            if ( empty( $toggle_status_nonce ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $toggle_status_nonce = sanitize_text_field( wp_unslash( $toggle_status_nonce ) );
            if ( !wp_verify_nonce( $toggle_status_nonce, 'epofw_toggle_status_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $product_id = filter_input( INPUT_POST, 'product_id', FILTER_SANITIZE_NUMBER_INT );
            $product_id = ( isset( $product_id ) ? sanitize_text_field( wp_unslash( $product_id ) ) : '' );
            $product_data = get_post( $product_id );
            if ( !$product_data ) {
                wp_send_json_error( array(
                    'msg' => __( 'Product not found.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $data = array();
            // Check if using custom tables.
            if ( EPOFW_Custom_Tables::is_enabled() ) {
                // Get current status from custom tables.
                global $wpdb;
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom table query for status toggle, caching not applicable for write operations.
                $current_status = $wpdb->get_var( $wpdb->prepare( "SELECT addon_status FROM {$wpdb->prefix}epofw_addons WHERE post_id = %d", $product_id ) );
                if ( 'on' === $current_status ) {
                    // Set to inactive.
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table update, no WordPress API equivalent.
                    $wpdb->update(
                        $wpdb->prefix . 'epofw_addons',
                        array(
                            'addon_status' => 'off',
                        ),
                        array(
                            'post_id' => $product_id,
                        ),
                        array('%s'),
                        array('%d')
                    );
                    // Also update post status for consistency.
                    wp_update_post( array(
                        'ID'          => $product_id,
                        'post_status' => 'draft',
                    ) );
                    $data['status'] = esc_html__( 'Inactive', 'extra-product-options-for-woocommerce' );
                    $data['class'] = 'inactive';
                } else {
                    // Set to active.
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table update, no WordPress API equivalent.
                    $wpdb->update(
                        $wpdb->prefix . 'epofw_addons',
                        array(
                            'addon_status' => 'on',
                        ),
                        array(
                            'post_id' => $product_id,
                        ),
                        array('%s'),
                        array('%d')
                    );
                    // Also update post status for consistency.
                    wp_update_post( array(
                        'ID'          => $product_id,
                        'post_status' => 'publish',
                    ) );
                    $data['status'] = esc_html__( 'Active', 'extra-product-options-for-woocommerce' );
                    $data['class'] = 'active';
                }
                // Clear cache.
                wp_cache_delete( "epofw_addon_{$product_id}", 'epofw' );
            } else {
                // Legacy: Use post_status only.
                $current_status = $product_data->post_status;
                if ( 'publish' === $current_status ) {
                    wp_update_post( array(
                        'ID'          => $product_id,
                        'post_status' => 'draft',
                    ) );
                    $data['status'] = esc_html__( 'Inactive', 'extra-product-options-for-woocommerce' );
                    $data['class'] = 'inactive';
                } else {
                    wp_update_post( array(
                        'ID'          => $product_id,
                        'post_status' => 'publish',
                    ) );
                    $data['status'] = esc_html__( 'Active', 'extra-product-options-for-woocommerce' );
                    $data['class'] = 'active';
                }
            }
            wp_send_json_success( array(
                'msg'     => __( 'Status toggled successfully.', 'extra-product-options-for-woocommerce' ),
                'content' => $data,
            ) );
        }

        /**
         * Get element edit form.
         *
         * @since 4.4.0
         */
        public function epofw_get_element_add_form() {
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_element_add_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $field_type = ( isset( $_POST['field_type'] ) ? sanitize_text_field( wp_unslash( $_POST['field_type'] ) ) : '' );
            if ( empty( $field_type ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Field type is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $element_id = ( isset( $_POST['element_id'] ) ? sanitize_text_field( wp_unslash( $_POST['element_id'] ) ) : '' );
            if ( empty( $element_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Element ID is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $epofw_get_post_id = ( isset( $_POST['addon_id'] ) ? absint( $_POST['addon_id'] ) : 0 );
            // When editing an existing addon, load field data from DB so options (e.g. productgroup products) display in the form.
            $epofw_field_data = null;
            if ( $epofw_get_post_id > 0 ) {
                $addon_data = epofw_get_data_from_db( $epofw_get_post_id );
                if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                    error_log( '[EPOFW ProductGroup] epofw_get_element_add_form: addon_id=' . $epofw_get_post_id . ' element_id=' . $element_id . ' field_type=' . $field_type . ' has_general=' . (( !empty( $addon_data['general'] ) ? 'yes' : 'no' )) );
                }
                if ( !empty( $addon_data['general'] ) && is_array( $addon_data['general'] ) ) {
                    foreach ( $addon_data['general'] as $section_data ) {
                        if ( empty( $section_data['row_groups'] ) || !is_array( $section_data['row_groups'] ) ) {
                            continue;
                        }
                        foreach ( $section_data['row_groups'] as $group_data ) {
                            if ( empty( $group_data['columns_groups'] ) || !is_array( $group_data['columns_groups'] ) ) {
                                continue;
                            }
                            foreach ( $group_data['columns_groups'] as $columns_group ) {
                                if ( empty( $columns_group['rows'] ) || !is_array( $columns_group['rows'] ) ) {
                                    continue;
                                }
                                foreach ( $columns_group['rows'] as $row_data ) {
                                    if ( !empty( $row_data['fields'][$element_id] ) && is_array( $row_data['fields'][$element_id] ) ) {
                                        $epofw_field_data = $row_data['fields'][$element_id];
                                        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                                            $opts = ( isset( $epofw_field_data['epofw_field_settings']['options'] ) ? $epofw_field_data['epofw_field_settings']['options'] : array() );
                                            $cnt = ( is_array( $opts ) ? count( $opts ) : 0 );
                                            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                                            error_log( '[EPOFW ProductGroup] epofw_get_element_add_form: FOUND field from DB, options count=' . $cnt . ', options=' . wp_json_encode( $opts ) );
                                        }
                                        break 4;
                                    }
                                }
                            }
                        }
                    }
                }
                if ( !is_array( $epofw_field_data ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                    error_log( '[EPOFW ProductGroup] epofw_get_element_add_form: field NOT found for element_id=' . $element_id . ', using empty form' );
                }
            }
            if ( !is_array( $epofw_field_data ) ) {
                $section_id = ( !empty( $_POST['section_id'] ) ? sanitize_text_field( wp_unslash( $_POST['section_id'] ) ) : 'section_' . wp_rand() );
                $group_id = ( !empty( $_POST['rows_data']['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rows_data']['group_id'] ) ) : 'group_' . wp_rand() );
                $row_id = ( !empty( $_POST['rows_data']['row_id'] ) ? sanitize_text_field( wp_unslash( $_POST['rows_data']['row_id'] ) ) : 'row_' . wp_rand() );
                $layout = ( !empty( $_POST['rows_data']['layout'] ) ? sanitize_text_field( wp_unslash( $_POST['rows_data']['layout'] ) ) : 'single' );
                $columns = ( !empty( $_POST['rows_data']['columns'] ) ? sanitize_text_field( wp_unslash( $_POST['rows_data']['columns'] ) ) : 1 );
                $epofw_field_data = array(
                    'field'                => array(
                        'type' => $field_type,
                    ),
                    'label'                => array(
                        'title' => '',
                    ),
                    'epofw_field_settings' => array(
                        'options' => array(),
                    ),
                );
            }
            $section_id = ( !empty( $_POST['section_id'] ) ? sanitize_text_field( wp_unslash( $_POST['section_id'] ) ) : (( isset( $epofw_field_data['row_association']['section_id'] ) ? $epofw_field_data['row_association']['section_id'] : 'section_' . wp_rand() )) );
            $epofw_section = array(
                'section_id' => $section_id,
            );
            $epofw_field_id = $element_id;
            ob_start();
            include EPOFW_PLUGIN_DIR . '/builder/element-form.php';
            $content = ob_get_clean();
            wp_send_json_success( array(
                'msg'     => __( 'Element found.', 'extra-product-options-for-woocommerce' ),
                'content' => $content,
            ) );
            wp_die();
        }

        /**
         * AJAX handler to get section settings form
         *
         * @since 4.4.0
         *
         * @return void
         */
        public function epofw_get_section_settings_form() {
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_element_add_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $section_id = ( isset( $_POST['section_id'] ) ? sanitize_text_field( wp_unslash( $_POST['section_id'] ) ) : '' );
            $section_order = ( isset( $_POST['section_order'] ) ? absint( wp_unslash( $_POST['section_order'] ) ) : 1 );
            if ( empty( $section_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Section ID is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Set default data for new section.
            // NOTE: Variable name MUST match what section-form.php expects (epofw_ prefix).
            $epofw_section = array(
                'section_id'    => $section_id,
                'section_order' => $section_order,
            );
            ob_start();
            include EPOFW_PLUGIN_DIR . '/builder/section-form.php';
            $content = ob_get_clean();
            wp_send_json_success( array(
                'msg'     => __( 'Section settings loaded.', 'extra-product-options-for-woocommerce' ),
                'content' => $content,
            ) );
            wp_die();
        }

        /**
         * AJAX handler to get row group settings form
         *
         * @since 4.4.0
         *
         * @return void
         */
        public function epofw_get_row_settings_form() {
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_element_add_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $section_id = ( isset( $_POST['section_id'] ) ? sanitize_text_field( wp_unslash( $_POST['section_id'] ) ) : '' );
            $group_id = ( isset( $_POST['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['group_id'] ) ) : '' );
            if ( empty( $section_id ) || empty( $group_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Section ID and Group ID are required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Set ALL required variables for row-form.php.
            // NOTE: Variable names MUST match what row-form.php expects (epofw_ prefix).
            $epofw_section_id = $section_id;
            $epofw_group_id = $group_id;
            $epofw_row_group_settings = array();
            // Empty array for new row group.
            ob_start();
            include EPOFW_PLUGIN_DIR . '/builder/row-form.php';
            $content = ob_get_clean();
            wp_send_json_success( array(
                'msg'     => __( 'Row settings loaded.', 'extra-product-options-for-woocommerce' ),
                'content' => $content,
            ) );
            wp_die();
        }

        /**
         * AJAX handler to get column settings form
         *
         * @since 4.4.0
         *
         * @return void
         */
        public function epofw_get_column_settings_form() {
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_element_add_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $section_id = ( isset( $_POST['section_id'] ) ? sanitize_text_field( wp_unslash( $_POST['section_id'] ) ) : '' );
            $group_id = ( isset( $_POST['group_id'] ) ? sanitize_text_field( wp_unslash( $_POST['group_id'] ) ) : '' );
            $row_id = ( isset( $_POST['row_id'] ) ? sanitize_text_field( wp_unslash( $_POST['row_id'] ) ) : '' );
            $sub_row_id = ( isset( $_POST['sub_row_id'] ) ? sanitize_text_field( wp_unslash( $_POST['sub_row_id'] ) ) : '' );
            $sub_row_order = ( isset( $_POST['sub_row_order'] ) ? absint( wp_unslash( $_POST['sub_row_order'] ) ) : 0 );
            if ( empty( $section_id ) || empty( $group_id ) || empty( $row_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Section ID, Group ID, and Row ID are required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Set ALL required variables for column-form.php.
            // NOTE: Variable names MUST match what column-form.php expects (epofw_ prefix).
            $epofw_section_id = $section_id;
            $epofw_group_id = $group_id;
            $epofw_row_id = $row_id;
            $epofw_column_settings = array(
                'sub_row_id'    => $sub_row_id,
                'sub_row_order' => $sub_row_order,
            );
            ob_start();
            include EPOFW_PLUGIN_DIR . '/builder/column-form.php';
            $content = ob_get_clean();
            wp_send_json_success( array(
                'msg'     => __( 'Column settings loaded.', 'extra-product-options-for-woocommerce' ),
                'content' => $content,
            ) );
            wp_die();
        }

        /**
         * Extract field types from addon data structure
         *
         * Supports multiple data structures:
         * 1. New custom tables structure: sections -> row_groups -> rows -> fields
         * 2. Old section structure: sections -> fields
         * 3. Legacy flat structure: direct fields in general
         *
         * @since 4.4.0 Updated to support custom tables structure with fields inside rows.
         *
         * @param array $addon_data The complete addon data array.
         *
         * @return array Array of field types with their details.
         */
        public static function extract_field_types( $addon_data ) {
            $field_types = array();
            // Check if general data exists.
            if ( !isset( $addon_data['general'] ) || !is_array( $addon_data['general'] ) ) {
                return $field_types;
            }
            // Loop through general data (could be fields or sections).
            foreach ( $addon_data['general'] as $item_key => $item_data ) {
                // Check if this is a section (has section_id or row_groups or fields array).
                if ( isset( $item_data['section_id'] ) || isset( $item_data['row_groups'] ) || isset( $item_data['fields'] ) ) {
                    // NEW v2.3: Check for columns_groups structure (fields inside row_groups -> columns_groups -> rows).
                    if ( isset( $item_data['row_groups'] ) && is_array( $item_data['row_groups'] ) ) {
                        foreach ( $item_data['row_groups'] as $group_id => $group_data ) {
                            // v2.3 structure: columns_groups -> rows -> fields.
                            if ( isset( $group_data['columns_groups'] ) && is_array( $group_data['columns_groups'] ) ) {
                                foreach ( $group_data['columns_groups'] as $columns_id => $columns_data ) {
                                    if ( isset( $columns_data['rows'] ) && is_array( $columns_data['rows'] ) ) {
                                        foreach ( $columns_data['rows'] as $row_id => $row_data ) {
                                            if ( isset( $row_data['fields'] ) && is_array( $row_data['fields'] ) ) {
                                                foreach ( $row_data['fields'] as $field_key => $field_data ) {
                                                    $field_types = self::add_field_to_types( $field_types, $field_key, $field_data );
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            // Legacy v2.0 structure: rows directly in row_groups.
                            if ( isset( $group_data['rows'] ) && is_array( $group_data['rows'] ) ) {
                                foreach ( $group_data['rows'] as $row_id => $row_data ) {
                                    if ( isset( $row_data['fields'] ) && is_array( $row_data['fields'] ) ) {
                                        foreach ( $row_data['fields'] as $field_key => $field_data ) {
                                            $field_types = self::add_field_to_types( $field_types, $field_key, $field_data );
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // FALLBACK: Check for old section structure (fields directly in section).
                    if ( isset( $item_data['fields'] ) && is_array( $item_data['fields'] ) ) {
                        foreach ( $item_data['fields'] as $field_key => $field_data ) {
                            $field_types = self::add_field_to_types( $field_types, $field_key, $field_data );
                        }
                    }
                } elseif ( isset( $item_data['field'] ) && isset( $item_data['field']['type'] ) ) {
                    // This is a direct field (old flat structure).
                    $field_types = self::add_field_to_types( $field_types, $item_key, $item_data );
                }
            }
            return $field_types;
        }

        /**
         * Helper to add field data to field types array
         *
         * @since 4.4.0
         *
         * @param array  $field_types Existing field types array.
         * @param string $field_key   Field key/ID.
         * @param array  $field_data  Field data array.
         *
         * @return array Updated field types array.
         */
        private static function add_field_to_types( $field_types, $field_key, $field_data ) {
            if ( isset( $field_data['field'] ) && isset( $field_data['field']['type'] ) ) {
                $field_type = $field_data['field']['type'];
                $field_title = ( isset( $field_data['label']['title'] ) ? $field_data['label']['title'] : '' );
                $field_status = ( isset( $field_data['field_status'] ) ? $field_data['field_status'] : 'off' );
                $field_settings = ( isset( $field_data['epofw_field_settings'] ) ? $field_data['epofw_field_settings'] : array() );
                $field_types[] = array(
                    'key'      => $field_key,
                    'type'     => $field_type,
                    'title'    => $field_title,
                    'status'   => $field_status,
                    'settings' => $field_settings,
                );
            }
            return $field_types;
        }

        /**
         * Get only field type names (simplified version).
         *
         * @param array $addon_data The complete addon data array.
         *
         * @return array Array of field type names.
         */
        public static function get_field_type_names( $addon_data ) {
            $field_types = self::extract_field_types( $addon_data );
            $type_names = array();
            foreach ( $field_types as $field ) {
                $type_names[] = $field['type'];
            }
            return $type_names;
        }

        /**
         * Get field types with counts.
         *
         * @param array $addon_data The complete addon data array.
         *
         * @return array Array with field type counts.
         */
        public static function get_field_type_counts( $addon_data ) {
            $field_types = self::get_field_type_names( $addon_data );
            return array_count_values( $field_types );
        }

        /**
         * Delete addon.
         *
         * @since 4.4.0
         */
        public function epofw_delete_addon() {
            $nonce = ( isset( $_POST['delete_addon_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['delete_addon_nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_delete_addon_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $product_id = ( isset( $_POST['get_post_id'] ) ? sanitize_text_field( wp_unslash( $_POST['get_post_id'] ) ) : '' );
            if ( empty( $product_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Product ID is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            /**
             * Fires before an addon is deleted.
             *
             * @since 4.4.5
             *
             * @param int $product_id The addon post ID being deleted.
             */
            do_action( 'epofw_before_delete_addon', $product_id );
            wp_delete_post( $product_id );
            /**
             * Fires after an addon has been deleted.
             *
             * @since 4.4.5
             *
             * @param int $product_id The addon post ID that was deleted.
             */
            do_action( 'epofw_after_delete_addon', $product_id );
            wp_send_json_success( array(
                'msg' => __( 'Addon deleted successfully.', 'extra-product-options-for-woocommerce' ),
            ) );
        }

        /**
         * AJAX handler to save addon data via JSON payload.
         * This bypasses PHP's max_input_vars limit by sending all data as a single JSON string.
         *
         * @since 4.4.0
         */
        public function epofw_ajax_save_addon() {
            // Verify nonce.
            $nonce = ( isset( $_POST['ajax_save_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['ajax_save_nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_ajax_save_addon' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Security check failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Check user capabilities.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'You do not have permission to perform this action.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Get the base64-encoded form data.
            $form_data_encoded = ( isset( $_POST['form_data_encoded'] ) ? $_POST['form_data_encoded'] : '' );
            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
            if ( empty( $form_data_encoded ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'No addon data received.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Decode from base64.
            $form_data_string = base64_decode( $form_data_encoded );
            // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
            if ( false === $form_data_string ) {
                wp_send_json_error( array(
                    'msg' => __( 'Invalid encoded data received.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Note: Don't use rawurldecode() here as it will decode %26 (&) prematurely.
            // The parse_form_data_unlimited() function will handle URL decoding properly.
            // jQuery serialize() encodes & as %26, so we need to keep it encoded until parsing.
            // Parse URL-encoded string MANUALLY to bypass max_input_vars limit.
            // parse_str() is subject to max_input_vars, so we parse it ourselves.
            $raw_post_data = self::parse_form_data_unlimited( $form_data_string );
            if ( empty( $raw_post_data ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Failed to parse form data.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Get post ID and action.
            $method_id = ( isset( $raw_post_data['get_post_id'] ) ? absint( $raw_post_data['get_post_id'] ) : 0 );
            $action = ( isset( $raw_post_data['action_type'] ) ? sanitize_text_field( $raw_post_data['action_type'] ) : 'add' );
            // Check if at least one section exists before parsing.
            $has_sections = !empty( $raw_post_data['epofw_section'] );
            if ( !$has_sections ) {
                wp_send_json_error( array(
                    'msg' => __( 'Please add at least one section before saving the addon.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Parse the addon data using the existing parser.
            $parsed_data = EPOFW_Post_Parser::parse_addon_data( $raw_post_data );
            if ( empty( $parsed_data ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Invalid addon data format. Please try again.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $new_epofw_data = $parsed_data;
            // Extract meta for wp_posts table.
            $post_title = ( isset( $new_epofw_data['epofw_addon_name'] ) ? sanitize_text_field( $new_epofw_data['epofw_addon_name'] ) : '' );
            $epofw_shipping_status = ( isset( $new_epofw_data['epofw_addon_status'] ) ? sanitize_text_field( $new_epofw_data['epofw_addon_status'] ) : 'on' );
            // Determine post status.
            $post_status = ( 'on' === $epofw_shipping_status ? 'publish' : 'draft' );
            // Get addon count for menu_order.
            $product_option_count = EPOFW_Field_Setting::epofw_count_method();
            // Create or update the post.
            if ( !empty( $method_id ) && $method_id > 0 ) {
                // Verify the post exists and is the correct post type before updating.
                $existing_post = get_post( $method_id );
                if ( !$existing_post || EPOFW_DFT_POST_TYPE !== $existing_post->post_type ) {
                    // Post doesn't exist or wrong type, create a new one instead.
                    $fee_post = array(
                        'post_title'  => $post_title,
                        'post_status' => $post_status,
                        'menu_order'  => $product_option_count + 1,
                        'post_type'   => EPOFW_DFT_POST_TYPE,
                    );
                    $method_id = wp_insert_post( $fee_post, true );
                    // Pass true to return WP_Error on failure.
                } else {
                    // Update existing post.
                    $fee_post = array(
                        'ID'          => $method_id,
                        'post_title'  => $post_title,
                        'post_status' => $post_status,
                        'post_type'   => EPOFW_DFT_POST_TYPE,
                    );
                    $method_id = wp_update_post( $fee_post, true );
                    // Pass true to return WP_Error on failure.
                }
            } else {
                // Create new post.
                $fee_post = array(
                    'post_title'  => $post_title,
                    'post_status' => $post_status,
                    'menu_order'  => $product_option_count + 1,
                    'post_type'   => EPOFW_DFT_POST_TYPE,
                );
                $method_id = wp_insert_post( $fee_post, true );
                // Pass true to return WP_Error on failure.
            }
            if ( is_wp_error( $method_id ) || empty( $method_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Failed to save addon post.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Reorganize fields from section level to row_groups structure.
            if ( EPOFW_Custom_Tables::is_enabled() && !empty( $new_epofw_data['general'] ) ) {
                foreach ( $new_epofw_data['general'] as $section_id => &$section_data ) {
                    if ( !empty( $section_data['fields'] ) && is_array( $section_data['fields'] ) ) {
                        // First pass: Group fields by group_id and layout.
                        $fields_by_group = array();
                        foreach ( $section_data['fields'] as $field_id => $field_data ) {
                            if ( !is_array( $field_data ) || !isset( $field_data['row_association'] ) ) {
                                continue;
                            }
                            $group_id = $field_data['row_association']['group_id'];
                            $row_id = ( isset( $field_data['row_association']['row_id'] ) ? $field_data['row_association']['row_id'] : '' );
                            $layout = ( isset( $field_data['row_association']['layout'] ) ? $field_data['row_association']['layout'] : 'single' );
                            // Generate group_id if empty.
                            if ( empty( $group_id ) ) {
                                $group_id = 'group_' . $section_id . '_' . $field_id;
                                $field_data['row_association']['group_id'] = $group_id;
                            }
                            // Generate row_id if empty.
                            if ( empty( $row_id ) ) {
                                $row_id = 'row_' . $section_id . '_' . $field_id;
                                $field_data['row_association']['row_id'] = $row_id;
                            }
                            if ( !isset( $fields_by_group[$group_id] ) ) {
                                $fields_by_group[$group_id] = array(
                                    'layout' => $layout,
                                    'fields' => array(),
                                );
                            }
                            $fields_by_group[$group_id]['fields'][$field_id] = $field_data;
                        }
                        // Second pass: Assign fields to rows.
                        foreach ( $fields_by_group as $group_id => $group_info ) {
                            $group_fields = $group_info['fields'];
                            $layout = $group_info['layout'];
                            // Ensure structure exists.
                            if ( !isset( $section_data['row_groups'][$group_id] ) ) {
                                $section_data['row_groups'][$group_id] = array(
                                    'row_group_settings' => array(
                                        'enabled' => '',
                                    ),
                                    'rows'               => array(),
                                );
                            }
                            // For multi-column, preserve original row_ids from each field.
                            if ( 'multiple' === $layout && count( $group_fields ) > 1 ) {
                                $column_number = 1;
                                foreach ( $group_fields as $field_id => $field_data ) {
                                    $original_row_id = $field_data['row_association']['row_id'];
                                    if ( !isset( $section_data['row_groups'][$group_id]['rows'][$original_row_id] ) ) {
                                        $section_data['row_groups'][$group_id]['rows'][$original_row_id] = array(
                                            'column_settings' => array(
                                                'enabled' => '',
                                            ),
                                            'row_number'      => $column_number,
                                            'fields'          => array(),
                                        );
                                    }
                                    $section_data['row_groups'][$group_id]['rows'][$original_row_id]['fields'][$field_id] = $field_data;
                                    ++$column_number;
                                }
                            } else {
                                // Single column: Use original row_id.
                                foreach ( $group_fields as $field_id => $field_data ) {
                                    $row_id = $field_data['row_association']['row_id'];
                                    if ( !isset( $section_data['row_groups'][$group_id]['rows'][$row_id] ) ) {
                                        $section_data['row_groups'][$group_id]['rows'][$row_id] = array(
                                            'column_settings' => array(
                                                'enabled' => '',
                                            ),
                                            'row_number'      => 1,
                                            'fields'          => array(),
                                        );
                                    }
                                    $section_data['row_groups'][$group_id]['rows'][$row_id]['fields'][$field_id] = $field_data;
                                }
                            }
                        }
                        // Remove fields from section level.
                        unset($section_data['fields']);
                    }
                }
                unset($section_data);
                // Break the reference.
                /**
                 * Filter addon data before saving to database.
                 *
                 * @since 4.4.5
                 *
                 * @param array $new_epofw_data The addon data to be saved.
                 * @param int   $method_id      The addon post ID.
                 * @param string $action        The action type ('add' or 'edit').
                 */
                $new_epofw_data = apply_filters(
                    'epofw_before_save_addon_data',
                    $new_epofw_data,
                    $method_id,
                    $action
                );
                // Save to custom tables.
                EPOFW_Custom_Tables::save_addon( $method_id, $new_epofw_data );
                /**
                 * Fires after addon has been saved to database.
                 *
                 * @since 4.4.5
                 *
                 * @param int    $method_id      The addon post ID.
                 * @param array  $new_epofw_data The saved addon data.
                 * @param string $action         The action type ('add' or 'edit').
                 */
                do_action(
                    'epofw_after_save_addon',
                    $method_id,
                    $new_epofw_data,
                    $action
                );
            }
            // Build redirect URL - use the same format as dynamic_url() function.
            $epofw_nonce = wp_create_nonce( 'edit_' . $method_id );
            $redirect_url = add_query_arg( array(
                'page'        => 'epofw-main',
                'tab'         => 'field-section',
                'action'      => 'edit',
                'post'        => $method_id,
                'epofw_nonce' => $epofw_nonce,
                'msg'         => ( 'add' === $action ? 'created' : 'saved' ),
            ), admin_url( 'admin.php' ) );
            wp_send_json_success( array(
                'msg'          => ( 'add' === $action ? __( 'Addon created successfully.', 'extra-product-options-for-woocommerce' ) : __( 'Addon saved successfully.', 'extra-product-options-for-woocommerce' ) ),
                'redirect_url' => $redirect_url,
                'post_id'      => $method_id,
            ) );
        }

        /**
         * Parse URL-encoded form data string without max_input_vars limit.
         * This is a custom implementation that bypasses PHP's max_input_vars restriction.
         *
         * @since 4.4.0
         * @param string $query_string URL-encoded query string.
         * @return array Parsed data as nested array.
         */
        private static function parse_form_data_unlimited( $query_string ) {
            $result = array();
            // Split by & - jQuery serialize() properly encodes & as %26 in values,
            // so unencoded & should only appear as parameter separators.
            $pairs = explode( '&', $query_string );
            foreach ( $pairs as $pair ) {
                if ( empty( $pair ) ) {
                    continue;
                }
                $parts = explode( '=', $pair, 2 );
                // Use rawurldecode to properly decode URL-encoded values (including %26 -> &).
                $name = ( isset( $parts[0] ) ? rawurldecode( $parts[0] ) : '' );
                $value = ( isset( $parts[1] ) ? rawurldecode( $parts[1] ) : '' );
                if ( empty( $name ) ) {
                    continue;
                }
                // Parse array notation like "epofw_field[123][label][title]".
                if ( preg_match( '/^([^\\[]+)(.*)$/', $name, $matches ) ) {
                    $base_name = $matches[1];
                    $keys_part = $matches[2];
                    if ( empty( $keys_part ) ) {
                        // Simple key=value.
                        $result[$base_name] = $value;
                    } else {
                        // Extract all keys from brackets.
                        preg_match_all( '/\\[([^\\]]*)\\]/', $keys_part, $key_matches );
                        $keys = $key_matches[1];
                        // Build nested structure.
                        $current =& $result;
                        // First, ensure base key exists.
                        if ( !isset( $current[$base_name] ) ) {
                            $current[$base_name] = array();
                        }
                        $current =& $current[$base_name];
                        // Navigate/create nested structure.
                        $last_index = count( $keys ) - 1;
                        foreach ( $keys as $i => $key ) {
                            if ( $i === $last_index ) {
                                // Last key - set the value.
                                if ( '' === $key ) {
                                    // Empty brackets [] means append to array.
                                    $current[] = $value;
                                } else {
                                    $current[$key] = $value;
                                }
                            } else {
                                // Not the last key - ensure array exists.
                                if ( '' === $key ) {
                                    // Empty brackets - append new array.
                                    if ( !is_array( $current ) ) {
                                        $current = array();
                                    }
                                    $current[] = array();
                                    $last_key = array_key_last( $current );
                                    if ( null === $last_key ) {
                                        $last_key = 0;
                                    }
                                    $current =& $current[$last_key];
                                } else {
                                    if ( !isset( $current[$key] ) || !is_array( $current[$key] ) ) {
                                        $current[$key] = array();
                                    }
                                    $current =& $current[$key];
                                }
                            }
                        }
                        unset($current);
                    }
                }
            }
            return $result;
        }

        /**
         * Duplicate addon.
         *
         * @since 4.4.0
         */
        public function epofw_duplicate_addon() {
            $nonce = ( isset( $_POST['duplicate_addon_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['duplicate_addon_nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_duplicate_addon_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $product_id = ( isset( $_POST['get_post_id'] ) ? sanitize_text_field( wp_unslash( $_POST['get_post_id'] ) ) : '' );
            if ( empty( $product_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Product ID is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $post = get_post( $product_id );
            if ( !$post ) {
                wp_send_json_error( array(
                    'msg' => __( 'Product not found.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Duplicate the post.
            $current_user = wp_get_current_user();
            $new_post_author = $current_user->ID;
            $args = array(
                'comment_status' => $post->comment_status,
                'ping_status'    => $post->ping_status,
                'post_author'    => $new_post_author,
                'post_content'   => $post->post_content,
                'post_excerpt'   => $post->post_excerpt,
                'post_name'      => $post->post_name,
                'post_parent'    => $post->post_parent,
                'post_password'  => $post->post_password,
                'post_status'    => 'draft',
                'post_title'     => $post->post_title . ' - duplicate',
                'post_type'      => $post->post_type,
                'to_ping'        => $post->to_ping,
                'menu_order'     => $post->menu_order,
            );
            $new_post_id = wp_insert_post( $args );
            if ( is_wp_error( $new_post_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Failed to duplicate addon.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Duplicate addon data from custom tables.
            $addon_data = EPOFW_Custom_Tables::load_addon( $product_id );
            if ( $addon_data ) {
                // Update name and status for duplicate.
                $addon_data['epofw_addon_name'] = $post->post_title . ' - duplicate';
                $addon_data['epofw_addon_status'] = 'off';
                /**
                 * Filter addon data before saving duplicate.
                 *
                 * @since 4.4.5
                 *
                 * @param array $addon_data   The addon data to be saved for duplicate.
                 * @param int   $new_post_id  The new duplicate addon post ID.
                 * @param int   $product_id   The original addon post ID.
                 */
                $addon_data = apply_filters(
                    'epofw_before_duplicate_addon_data',
                    $addon_data,
                    $new_post_id,
                    $product_id
                );
                // Save to custom tables.
                EPOFW_Custom_Tables::save_addon( $new_post_id, $addon_data );
            }
            /**
             * Fires after an addon has been duplicated.
             *
             * @since 4.4.5
             *
             * @param int $new_post_id The new duplicate addon post ID.
             * @param int $product_id  The original addon post ID.
             */
            do_action( 'epofw_after_duplicate_addon', $new_post_id, $product_id );
            $edit_url = add_query_arg( array(
                'page'        => 'epofw-main',
                'tab'         => 'field-section',
                'action'      => 'edit',
                'post'        => $new_post_id,
                'epofw_nonce' => wp_create_nonce( 'edit_' . $new_post_id ),
            ), admin_url( 'admin.php' ) );
            wp_send_json_success( array(
                'msg'            => __( 'Addon duplicated successfully.', 'extra-product-options-for-woocommerce' ),
                'new_product_id' => $new_post_id,
                'edit_url'       => $edit_url,
                'post_data'      => get_post( $new_post_id ),
                'updated_at'     => __( 'Updated at', 'extra-product-options-for-woocommerce' ),
                'status'         => __( 'Inactive', 'extra-product-options-for-woocommerce' ),
            ) );
        }

        /**
         * Migrate all addons to sections (AJAX handler)
         *
         * @since 5.0.0
         */
        public function epofw_migrate_to_sections() {
            // Verify nonce.
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_migrate_to_sections_nonce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Security check failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Check user capability.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'You do not have permission to perform this action.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Run migration.
            if ( !class_exists( 'EPOFW_Migration' ) ) {
                require_once EPOFW_PLUGIN_DIR_PATH . 'includes/class-epofw-migration.php';
            }
            $results = EPOFW_Migration::migrate_to_custom_tables();
            // Handle case where there are only errors and no successes.
            if ( (int) $results['errors'] > 0 && 0 === (int) $results['success'] ) {
                wp_send_json_error( array(
                    'message' => __( 'Migration failed. Please check the error log.', 'extra-product-options-for-woocommerce' ),
                    'data'    => array(
                        'total_count'    => $results['total'],
                        'migrated_count' => $results['success'],
                        'errors'         => $results['messages'],
                    ),
                ) );
            }
            // Mark migration as complete so button is hidden.
            update_option( 'epofw_row_association_migration_done', true );
            // Build appropriate message based on results.
            $skipped = ( isset( $results['skipped'] ) ? $results['skipped'] : 0 );
            if ( $results['success'] > 0 ) {
                $message = sprintf( 
                    /* translators: %1$d: number of migrated addons, %2$d: number of transformed addons */
                    __( 'Successfully migrated %1$d addons (%2$d transformed from old structure).', 'extra-product-options-for-woocommerce' ),
                    $results['success'],
                    $results['transformed']
                 );
            } elseif ( $skipped > 0 ) {
                $message = sprintf( 
                    /* translators: %d: number of skipped addons */
                    __( 'Migration complete. %d addons were already migrated or had no data to migrate.', 'extra-product-options-for-woocommerce' ),
                    $skipped
                 );
            } else {
                $message = __( 'Migration complete. No addons found to migrate.', 'extra-product-options-for-woocommerce' );
            }
            wp_send_json_success( array(
                'message' => $message,
                'data'    => array(
                    'total_count'    => $results['total'],
                    'migrated_count' => $results['success'],
                    'transformed'    => $results['transformed'],
                    'skipped'        => $skipped,
                    'errors'         => ( $results['errors'] > 0 ? $results['messages'] : array() ),
                ),
            ) );
        }

        /**
         * Export addon configuration as JSON (Dev Tool)
         *
         * @since 4.5.0
         */
        public function epofw_export_addon() {
            // Verify nonce.
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_admin_nonce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Nonce verification failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Check user permissions.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'You do not have permission to export addons.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $addon_id = ( isset( $_POST['addon_id'] ) ? absint( $_POST['addon_id'] ) : 0 );
            if ( empty( $addon_id ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Addon ID is required.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Get addon data from custom tables.
            $addon_data = EPOFW_Custom_Tables::load_addon( $addon_id );
            if ( empty( $addon_data ) ) {
                wp_send_json_error( array(
                    'msg' => __( 'Addon data not found.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Get post title for filename.
            $post = get_post( $addon_id );
            $post_title = ( $post ? $post->post_title : 'addon' );
            $filename = sanitize_file_name( strtolower( str_replace( ' ', '-', $post_title ) ) ) . '-export-' . time() . '.json';
            wp_send_json_success( array(
                'msg'        => __( 'Addon exported successfully.', 'extra-product-options-for-woocommerce' ),
                'addon_data' => $addon_data,
                'filename'   => $filename,
            ) );
        }

        /**
         * Save view preference to user meta
         *
         * @since 1.0.0
         */
        public function epofw_save_view_preference() {
            // Verify nonce.
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_admin_nonce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Security check failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Check user capabilities.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Insufficient permissions.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            $view = ( isset( $_POST['view'] ) ? sanitize_text_field( wp_unslash( $_POST['view'] ) ) : '' );
            // Validate view type.
            $allowed_views = array('grid', 'list');
            if ( !in_array( $view, $allowed_views, true ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Invalid view type.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            update_option( 'epofw_view_preference', $view );
            wp_send_json_success( array(
                'message' => __( 'View preference saved.', 'extra-product-options-for-woocommerce' ),
            ) );
        }

        /**
         * AJAX handler for searching addons.
         *
         * Searches addons by name and field types in the database.
         * Supports pagination-compatible server-side filtering.
         *
         * @since 4.4.5
         */
        public function epofw_search_addons() {
            // Verify nonce.
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'epofw_admin_nonce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Security check failed.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Check user capabilities.
            if ( !current_user_can( 'manage_woocommerce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Insufficient permissions.', 'extra-product-options-for-woocommerce' ),
                ) );
            }
            // Get search parameters.
            $search_term = ( isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '' );
            $status = ( isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : 'all' );
            $page = ( isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1 );
            $per_page = ( isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 50 );
            // Ensure edit URLs include a valid admin page/tab in AJAX context.
            $current_page = self::epofw_current_page();
            if ( empty( $current_page ) ) {
                $current_page = 'epofw-main';
            }
            $current_tab = self::epofw_current_tab();
            if ( empty( $current_tab ) ) {
                $current_tab = 'field-section';
            }
            global $wpdb;
            // Build query based on storage method.
            if ( EPOFW_Custom_Tables::is_enabled() ) {
                // Query from custom tables.
                $where_clauses = array('1=1');
                $where_values = array();
                // Search by addon name.
                if ( !empty( $search_term ) ) {
                    $where_clauses[] = 'a.addon_name LIKE %s';
                    $where_values[] = '%' . $wpdb->esc_like( $search_term ) . '%';
                }
                // Filter by status.
                if ( 'all' !== $status && in_array( $status, array('active', 'inactive'), true ) ) {
                    $status_value = ( 'active' === $status ? 'on' : 'off' );
                    $where_clauses[] = 'a.addon_status = %s';
                    $where_values[] = $status_value;
                }
                $where_sql = implode( ' AND ', $where_clauses );
                // Get total count.
                // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
                $total_query = $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}epofw_addons a\n\t\t\t\t\tINNER JOIN {$wpdb->posts} p ON a.post_id = p.ID AND p.post_type = %s\n\t\t\t\t\tWHERE {$where_sql}", array_merge( array(EPOFW_DFT_POST_TYPE), $where_values ) );
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Query is prepared above.
                $total_count = (int) $wpdb->get_var( $total_query );
                // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
                // Get paginated results.
                $offset = ($page - 1) * $per_page;
                // Note: $where_sql contains only hardcoded SQL fragments with placeholders; values are passed via prepare().
                // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
                $results_query = $wpdb->prepare( "SELECT a.id, a.post_id, a.addon_name, a.addon_status, a.updated_at\n\t\t\t\t\tFROM {$wpdb->prefix}epofw_addons a\n\t\t\t\t\tINNER JOIN {$wpdb->posts} p ON a.post_id = p.ID AND p.post_type = %s\n\t\t\t\t\tWHERE {$where_sql}\n\t\t\t\t\tORDER BY a.id DESC\n\t\t\t\t\tLIMIT %d OFFSET %d", array_merge( array(EPOFW_DFT_POST_TYPE), $where_values, array($per_page, $offset) ) );
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Query is prepared above.
                $addons = $wpdb->get_results( $results_query );
                // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
            } else {
                // Fallback to wp_posts query.
                $args = array(
                    'post_type'      => EPOFW_DFT_POST_TYPE,
                    'post_status'    => 'any',
                    'posts_per_page' => $per_page,
                    'paged'          => $page,
                    'orderby'        => 'ID',
                    'order'          => 'DESC',
                );
                // Search by title.
                if ( !empty( $search_term ) ) {
                    $args['s'] = $search_term;
                }
                // Filter by status.
                if ( 'all' !== $status && in_array( $status, array('active', 'inactive'), true ) ) {
                    $args['post_status'] = ( 'active' === $status ? 'publish' : 'draft' );
                }
                $query = new WP_Query($args);
                $addons = $query->posts;
                $total_count = $query->found_posts;
            }
            // Format results for response.
            $formatted_addons = array();
            foreach ( $addons as $addon ) {
                if ( EPOFW_Custom_Tables::is_enabled() ) {
                    $addon_id = $addon->post_id;
                    $addon_name = ( !empty( $addon->addon_name ) ? $addon->addon_name : 'Addon ' . $addon->post_id );
                    $addon_status = $addon->addon_status;
                    $addon_updated = $addon->updated_at;
                } else {
                    $addon_id = $addon->ID;
                    $addon_name = get_the_title( $addon->ID );
                    $addon_status = ( 'publish' === $addon->post_status ? 'on' : 'off' );
                    $addon_updated = $addon->post_modified;
                }
                // Get addon data for field types and rules.
                $addon_data = epofw_get_data_from_db( $addon_id );
                $field_types = self::get_field_type_names( $addon_data );
                $additional_rules = epofw_check_array_key_exists( 'additional_rule_data', $addon_data );
                // Build usage info.
                $usage_info = $this->get_addon_usage_info( $additional_rules );
                $formatted_addons[] = array(
                    'id'          => $addon_id,
                    'name'        => $addon_name,
                    'status'      => ( 'on' === $addon_status ? 'active' : 'inactive' ),
                    'status_text' => ( 'on' === $addon_status ? __( 'Active', 'extra-product-options-for-woocommerce' ) : __( 'Inactive', 'extra-product-options-for-woocommerce' ) ),
                    'updated'     => $addon_updated,
                    'field_types' => array_map( 'ucfirst', $field_types ),
                    'usage'       => $usage_info,
                    'edit_url'    => wp_nonce_url( self::dynamic_url(
                        $current_page,
                        $current_tab,
                        'edit',
                        $addon_id
                    ), 'edit_' . $addon_id, 'epofw_nonce' ),
                );
            }
            wp_send_json_success( array(
                'addons'      => $formatted_addons,
                'total'       => $total_count,
                'page'        => $page,
                'per_page'    => $per_page,
                'total_pages' => ceil( $total_count / $per_page ),
                'search'      => $search_term,
                'status'      => $status,
            ) );
        }

        /**
         * Get addon usage information for display.
         *
         * @since 4.4.5
         *
         * @param array $additional_rules Additional rules data.
         * @return array Usage information.
         */
        private function get_addon_usage_info( $additional_rules ) {
            $usage = array(
                'products'   => array(),
                'categories' => array(),
                'tags'       => array(),
                'variations' => array(),
                'user_roles' => array(),
            );
            if ( empty( $additional_rules ) ) {
                return $usage;
            }
            // Normalize rules data.
            $normalized_rules = epofw_normalize_additional_rules_data( $additional_rules );
            $all_conditions = array();
            if ( !empty( $normalized_rules['groups'] ) && is_array( $normalized_rules['groups'] ) ) {
                foreach ( $normalized_rules['groups'] as $group ) {
                    if ( !empty( $group['conditions'] ) && is_array( $group['conditions'] ) ) {
                        foreach ( $group['conditions'] as $condition ) {
                            if ( !empty( $condition['condition'] ) && !empty( $condition['value'] ) ) {
                                $all_conditions[] = $condition;
                            }
                        }
                    }
                }
            } else {
                foreach ( $additional_rules as $rule ) {
                    if ( !empty( $rule ) && is_array( $rule ) && !empty( $rule['condition'] ) && !empty( $rule['value'] ) ) {
                        $all_conditions[] = $rule;
                    }
                }
            }
            foreach ( $all_conditions as $rule ) {
                $condition_type = $rule['condition'];
                $values = $rule['value'];
                switch ( $condition_type ) {
                    case 'product':
                        foreach ( array_slice( $values, 0, 3 ) as $product_id ) {
                            $usage['products'][] = array(
                                'id'   => $product_id,
                                'name' => get_the_title( $product_id ),
                                'url'  => get_permalink( $product_id ),
                            );
                        }
                        $usage['products_total'] = count( $values );
                        break;
                    case 'category':
                        foreach ( array_slice( $values, 0, 3 ) as $cat_id ) {
                            $term = get_term( $cat_id, 'product_cat' );
                            if ( !is_wp_error( $term ) && $term ) {
                                $usage['categories'][] = array(
                                    'id'   => $cat_id,
                                    'name' => $term->name,
                                    'url'  => get_term_link( $term ),
                                );
                            }
                        }
                        $usage['categories_total'] = count( $values );
                        break;
                    case 'tag':
                        foreach ( array_slice( $values, 0, 3 ) as $tag_id ) {
                            $term = get_term( $tag_id, 'product_tag' );
                            if ( !is_wp_error( $term ) && $term ) {
                                $usage['tags'][] = array(
                                    'id'   => $tag_id,
                                    'name' => $term->name,
                                    'url'  => get_term_link( $term ),
                                );
                            }
                        }
                        $usage['tags_total'] = count( $values );
                        break;
                    case 'product_variation':
                        foreach ( array_slice( $values, 0, 3 ) as $var_id ) {
                            $usage['variations'][] = array(
                                'id'   => $var_id,
                                'name' => get_the_title( $var_id ),
                                'url'  => get_permalink( $var_id ),
                            );
                        }
                        $usage['variations_total'] = count( $values );
                        break;
                    case 'user_role':
                        $wp_roles = wp_roles();
                        foreach ( array_slice( $values, 0, 3 ) as $role_slug ) {
                            $role_name = ( isset( $wp_roles->role_names[$role_slug] ) ? translate_user_role( $wp_roles->role_names[$role_slug] ) : ucfirst( $role_slug ) );
                            $usage['user_roles'][] = array(
                                'slug' => $role_slug,
                                'name' => $role_name,
                            );
                        }
                        $usage['user_roles_total'] = count( $values );
                        break;
                }
            }
            return $usage;
        }

    }

}
$epofw_admin = new EPOFW_Admin();