Bende scriptlerimde datatables kullanıyorum. server side classı bana çok karmaşık gelmişti. class kullanmadan ajax postun yapıldığı her tablo istekleri için. Şu yapıda bir kodum var. Kendinize göre düzenleyebilirsiniz.
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' and $_SERVER['HTTP_REFERER'] == site_url('admin-duyurular')) {
    $toplam_veri = $db->from('menu')
    ->select('count(id) as total')
    ->total();
    $query = '';
    $output = array();
    $query .= 'SELECT * FROM duyurular ';

    if(isset($_POST["search"]["value"])) {
        $query .= 'WHERE duyuru LIKE "%'.$_POST["search"]["value"].'%"';
        $query .= 'OR link LIKE "%'.$_POST["search"]["value"].'%"';
    }
    $columns = array(
        0 => 'duyuru',
        1 => 'link'
    );
 
    if(isset($_POST["order"])) {
        $query .= ' ORDER BY '. $columns[$_POST['order'][0]['column']].' '.$_POST['order']['0']['dir'].' ';
    } else {
        $query .= ' ORDER BY id DESC ';
    }
    if($_POST["length"] != -1) {
        $query .= 'LIMIT '.$_POST['start'].','.$_POST['length'];
    }
    $statement = $db->prepare($query);
    $statement->execute();
    $result = $statement->fetchAll();
    $data = array();
    $filtered_rows = $statement->rowCount();
    foreach($result as $row) {
        $sub_array = array();

        $sub_array[] = $row["duyuru"];
        $sub_array[] = $row["link"];
        $sub_array[] = '<button type="button" name="sil" id="'.$row["id"].'" class="btn btn-danger btn-xs sil"><i class="fa fa-trash"></i></button>';
        $data[] = $sub_array;
    }
    $output = array(
        "draw" => intval($_POST["draw"]),
        "recordsTotal" => $filtered_rows,
        "recordsFiltered" => $toplam_veri,
        "data" => $data
    );
    echo json_encode($output);
}
Sonuç Mükemmel

https://www.youtube.com/watch?v=XQsUYC67SE0