if ( ! defined('ABSPATH') ) { exit; }
    if ( ! class_exists('WP_List_Table') ) {
        require_once ABSPATH.'wp-admin/includes/class-wp-list-table.php';
    }
    class Ado_Fix_404_List_Table extends WP_List_Table {
        public function get_columns() {
            return array(
                'cb'        => '',
                'from_path' => __('Desde','ado-fix-404'),
                'to_url'    => __('Hacia','ado-fix-404'),
                'status'    => __('Estado','ado-fix-404'),
                'approved'  => __('Aprobado','ado-fix-404'),
                'hits'      => __('Hits','ado-fix-404'),
                'source'    => __('Origen','ado-fix-404'),
                'updated_at'=> __('Actualizado','ado-fix-404'),
            );
        }
public function column_default( $item, $column_name ) {
            switch ( $column_name ) {
                case 'approved':
                    return ! empty( $item['approved'] )
                        ? esc_html__( 'Sí', 'ado-fix-404' )
                        : esc_html__( 'No', 'ado-fix-404' );
                case 'status':
                    $val = $item['status'] ?? $item['http_code'] ?? '';
                    return $val !== '' ? esc_html( (string) $val ) : '';
                case 'hits':
                    return isset($item['hits']) ? intval($item['hits']) : 0;
                case 'source':
                    $val = $item['source'] ?? $item['source_type'] ?? '';
                    return $val !== '' ? esc_html( (string) $val ) : '';
                case 'updated_at':
                    return isset($item['updated_at']) ? esc_html( (string) $item['updated_at'] ) : '';
                default:
                    return isset($item[$column_name]) ? esc_html( (string) $item[$column_name] ) : '';
            }
        }
        protected function column_cb($item) {
            return sprintf('', intval($item['id']));
        }
        protected function column_from_path($item) {
            $approve_url = wp_nonce_url( add_query_arg(array('page'=>'ado-fix-404','ado_approve'=>$item['id'])), 'ado_fix404_row_action_'.$item['id'] );
            $discard_url = wp_nonce_url( add_query_arg(array('page'=>'ado-fix-404','ado_discard'=>$item['id'])), 'ado_fix404_row_action_'.$item['id'] );
            $actions = array();
            if ( ! $item['approved'] ) {
                $actions['approve'] = ''.esc_html__('Aprobar','ado-fix-404').'';
                $actions['discard'] = ''.esc_html__('Descartar','ado-fix-404').'';
            }
            return sprintf('%s %s', esc_html($item['from_path']), $this->row_actions($actions));
        }
        public function column_to_url( $item ) {
            $raw = $item['to_url'] ?? $item['target_url'] ?? '';
            if ( $raw === '' ) {
                return '';
            }
            $url   = esc_url( $raw );
            $label = esc_html( wp_parse_url( $raw, PHP_URL_PATH ) ?: $raw );
            return sprintf( '%s', $url, $label );
        }
function prepare_items() {
            global $wpdb;
            $table = $wpdb->prefix.'ado_fix_redirects';
            if ( isset($_GET['ado_approve']) && wp_verify_nonce($_GET['_wpnonce'] ?? '', 'ado_fix404_row_action_'.intval($_GET['ado_approve'])) ) {
                if ( current_user_can('manage_options') ) {
                    $wpdb->update($table, array('approved'=>1,'updated_at'=>current_time('mysql')), array('id'=>intval($_GET['ado_approve'])));
                }
            }
            if ( isset($_GET['ado_discard']) && wp_verify_nonce($_GET['_wpnonce'] ?? '', 'ado_fix404_row_action_'.intval($_GET['ado_discard'])) ) {
                if ( current_user_can('manage_options') ) {
                    $wpdb->delete($table, array('id'=>intval($_GET['ado_discard'])));
                }
            }
            $where = 'WHERE 1=1';
            if ( ! empty($_REQUEST['s']) ) {
                $like = '%'.$wpdb->esc_like( sanitize_text_field(wp_unslash($_REQUEST['s'])) ).'%';
                $where .= $wpdb->prepare(' AND (from_path LIKE %s OR to_url LIKE %s)', $like, $like);
            }
            if ( isset($_GET['status']) && in_array($_GET['status'], array('301','410'), true) ) {
                $where .= $wpdb->prepare(' AND status = %d', intval($_GET['status']));
            }
            if ( isset($_GET['approved']) && in_array($_GET['approved'], array('0','1'), true) ) {
                $where .= $wpdb->prepare(' AND approved = %d', intval($_GET['approved']));
            }
            if ( isset($_GET['source']) && $_GET['source'] !== '' ) {
                $where .= $wpdb->prepare(' AND source = %s', sanitize_text_field($_GET['source']));
            }
            $orderby = in_array(isset($_GET['orderby']) ? $_GET['orderby'] : '', array('created_at','updated_at','hits'), true) ? $_GET['orderby'] : 'created_at';
            $order   = in_array(strtoupper(isset($_GET['order']) ? $_GET['order'] : ''), array('ASC','DESC'), true) ? strtoupper($_GET['order']) : 'DESC';
            $per_page = $this->get_items_per_page('ado_fix404_per_page', ado_fix404_get_options()['per_page_default']);
            $paged    = max(1, intval(isset($_GET['paged']) ? $_GET['paged'] : 1));
            $offset   = ($paged - 1) * $per_page;
            $total    = intval( $wpdb->get_var("SELECT COUNT(*) FROM {$table} {$where}") );
            $items    = $wpdb->get_results( $wpdb->prepare("SELECT id, from_path, COALESCE(to_url, target_url) AS to_url, COALESCE(status, http_code) AS status, approved, hits, COALESCE(source, source_type) AS source, updated_at FROM {$table} {$where} ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d", $per_page, $offset ), ARRAY_A );
            $this->items = $items;
            $this->_column_headers = array($this->get_columns(), array(), array());
            $this->set_pagination_args(array(
                'total_items' => $total,
                'per_page'    => $per_page,
                'total_pages' => ceil($total / $per_page),
            ));
        }
    }