Admin

table = $wpdb->prefix . ‘geis_payments’; register_activation_hook(__FILE__, [$this, ‘activate’]); add_action(‘rest_api_init’, [$this, ‘register_routes’]); add_action(‘admin_menu’, [$this, ‘admin_menu’]); add_action(‘admin_enqueue_scripts’, [$this, ‘admin_assets’]); add_action(‘wp_enqueue_scripts’, [$this, ‘frontend_assets’]); add_action(‘admin_post_geis_export_csv’, [$this, ‘export_csv’]); } public function activate() { global $wpdb; require_once ABSPATH . ‘wp-admin/includes/upgrade.php’; $charset = $wpdb->get_charset_collate(); $sql = “CREATE TABLE {$this->table} ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, transaction_id varchar(40) NOT NULL, created_at datetime NOT NULL, updated_at datetime NOT NULL, name varchar(190) NOT NULL, whatsapp varchar(40) NOT NULL, address text NULL, join_status varchar(80) NULL, package text NULL, package_quantity varchar(50) NULL, variant varchar(190) NULL, notes text NULL, referral_name varchar(190) NULL, referral_whatsapp varchar(40) NULL, referral_city varchar(190) NULL, landing_page text NULL, amount decimal(15,2) NOT NULL DEFAULT 0, payment_method varchar(80) NULL, payment_status varchar(40) NOT NULL DEFAULT ‘pending’, proof_url text NULL, admin_notes text NULL, paid_at datetime NULL, PRIMARY KEY (id), UNIQUE KEY transaction_id (transaction_id), KEY payment_status (payment_status), KEY created_at (created_at), KEY whatsapp (whatsapp) ) $charset;”; dbDelta($sql); update_option(‘geis_pd_version’, GEIS_PD_VERSION); } public function register_routes() { register_rest_route(‘geis/v1’, ‘/register’, [ ‘methods’ => ‘POST’, ‘callback’ => [$this, ‘create_registration’], ‘permission_callback’ => ‘__return_true’, ]); register_rest_route(‘geis/v1’, ‘/payment/(?P\d+)’, [ ‘methods’ => ‘POST’, ‘callback’ => [$this, ‘update_payment’], ‘permission_callback’ => function() { return current_user_can(‘manage_options’); }, ]); } private function clean($value) { if (is_array($value)) return array_map([$this, ‘clean’], $value); return sanitize_textarea_field((string)$value); } private function transaction_id() { global $wpdb; do { $id = ‘GEIS-‘ . wp_date(‘Ymd’) . ‘-‘ . strtoupper(wp_generate_password(6, false, false)); $exists = $wpdb->get_var($wpdb->prepare(“SELECT id FROM {$this->table} WHERE transaction_id=%s”, $id)); } while ($exists); return $id; } public function create_registration(WP_REST_Request $request) { global $wpdb; $data = $request->get_json_params(); if (!is_array($data)) $data = $request->get_params(); $name = $this->clean($data[‘name’] ?? ”); $wa = $this->clean($data[‘whatsapp’] ?? ”); if ($name === ” || $wa === ”) { return new WP_REST_Response([‘success’=>false,’message’=>’Nama dan WhatsApp wajib diisi.’], 400); } // Basic anti-spam: same WA + same name within 30 seconds is treated as duplicate. $recent = $wpdb->get_var($wpdb->prepare( “SELECT transaction_id FROM {$this->table} WHERE whatsapp=%s AND name=%s AND created_at >= %s ORDER BY id DESC LIMIT 1″, $wa, $name, gmdate(‘Y-m-d H:i:s’, time()-30) )); if ($recent) { return new WP_REST_Response([‘success’=>true,’duplicate’=>true,’transaction_id’=>$recent], 200); } $now = current_time(‘mysql’); $transaction = $this->transaction_id(); $row = [ ‘transaction_id’ => $transaction, ‘created_at’ => $now, ‘updated_at’ => $now, ‘name’ => $name, ‘whatsapp’ => $wa, ‘address’ => $this->clean($data[‘address’] ?? ”), ‘join_status’ => $this->clean($data[‘join_status’] ?? ‘Gabung Bisnis’), ‘package’ => $this->clean($data[‘package’] ?? ”), ‘package_quantity’ => $this->clean($data[‘package_quantity’] ?? ”), ‘variant’ => $this->clean($data[‘variant’] ?? ”), ‘notes’ => $this->clean($data[‘notes’] ?? ”), ‘referral_name’ => $this->clean($data[‘referral_name’] ?? ”), ‘referral_whatsapp’ => $this->clean($data[‘referral_whatsapp’] ?? ”), ‘referral_city’ => $this->clean($data[‘referral_city’] ?? ”), ‘landing_page’ => esc_url_raw($data[‘landing_page’] ?? ”), ‘amount’ => (float)($data[‘amount’] ?? 0), ‘payment_method’ => $this->clean($data[‘payment_method’] ?? ‘Transfer Manual’), ‘payment_status’ => ‘pending’, ]; $formats = [‘%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%s’,’%f’,’%s’,’%s’]; $ok = $wpdb->insert($this->table, $row, $formats); if (!$ok) return new WP_REST_Response([‘success’=>false,’message’=>’Gagal menyimpan pendaftaran.’], 500); return new WP_REST_Response([ ‘success’=>true, ‘transaction_id’=>$transaction, ‘id’=>(int)$wpdb->insert_id, ‘message’=>’Pendaftaran tersimpan.’ ], 201); } public function update_payment(WP_REST_Request $request) { global $wpdb; $id = absint($request[‘id’]); $data = $request->get_json_params(); if (!is_array($data)) $data = $request->get_params(); $allowed_status = [‘pending’,’waiting_verification’,’paid’,’cancelled’]; $status = sanitize_key($data[‘payment_status’] ?? ‘pending’); if (!in_array($status, $allowed_status, true)) $status = ‘pending’; $amount = isset($data[‘amount’]) ? (float)$data[‘amount’] : 0; $method = $this->clean($data[‘payment_method’] ?? ”); $admin_notes = $this->clean($data[‘admin_notes’] ?? ”); $proof = esc_url_raw($data[‘proof_url’] ?? ”); $paid_at = ($status === ‘paid’) ? current_time(‘mysql’) : null; $updated = $wpdb->update($this->table, [ ‘payment_status’=>$status, ‘amount’=>$amount, ‘payment_method’=>$method, ‘proof_url’=>$proof, ‘admin_notes’=>$admin_notes, ‘paid_at’=>$paid_at, ‘updated_at’=>current_time(‘mysql’) ], [‘id’=>$id], [‘%s’,’%f’,’%s’,’%s’,’%s’,’%s’,’%s’], [‘%d’]); if ($updated === false) return new WP_REST_Response([‘success’=>false,’message’=>’Gagal memperbarui.’], 500); return [‘success’=>true]; } public function admin_menu() { add_menu_page(‘GEIS Payment Dashboard’,’GEIS Payments’,’manage_options’,’geis-payment-dashboard’,[$this,’dashboard_page’],’dashicons-chart-area’,26); } public function admin_assets($hook) { if ($hook !== ‘toplevel_page_geis-payment-dashboard’) return; wp_enqueue_style(‘geis-pd-admin’, GEIS_PD_URL.’assets/css/admin.css’, [], GEIS_PD_VERSION); wp_enqueue_script(‘geis-pd-admin’, GEIS_PD_URL.’assets/js/admin.js’, [], GEIS_PD_VERSION, true); wp_localize_script(‘geis-pd-admin’,’GEIS_PD’,[ ‘rest’=>esc_url_raw(rest_url(‘geis/v1’)), ‘nonce’=>wp_create_nonce(‘wp_rest’), ‘ajax’=>admin_url(‘admin-post.php’), ]); } public function frontend_assets() { wp_enqueue_script(‘geis-pd-front’, GEIS_PD_URL.’assets/js/frontend.js’, [], GEIS_PD_VERSION, true); wp_localize_script(‘geis-pd-front’,’GEIS_PD_FRONT’,[ ‘endpoint’=>esc_url_raw(rest_url(‘geis/v1/register’)), ]); } private function get_rows() { global $wpdb; $search = isset($_GET[‘s’]) ? sanitize_text_field(wp_unslash($_GET[‘s’])) : ”; $status = isset($_GET[‘status’]) ? sanitize_key($_GET[‘status’]) : ”; $from = isset($_GET[‘from’]) ? sanitize_text_field($_GET[‘from’]) : ”; $to = isset($_GET[‘to’]) ? sanitize_text_field($_GET[‘to’]) : ”; $where = [‘1=1′]; $args=[]; if ($search !== ”) { $like=’%’.$wpdb->esc_like($search).’%’; $where[]='(transaction_id LIKE %s OR name LIKE %s OR whatsapp LIKE %s OR referral_name LIKE %s)’; array_push($args,$like,$like,$like,$like); } if ($status && in_array($status,[‘pending’,’waiting_verification’,’paid’,’cancelled’],true)) { $where[]=’payment_status=%s’; $args[]=$status; } if ($from) { $where[]=’DATE(created_at) >= %s’; $args[]=$from; } if ($to) { $where[]=’DATE(created_at) <= %s'; $args[]=$to; } $sql='SELECT * FROM '.$this->table.’ WHERE ‘.implode(‘ AND ‘,$where).’ ORDER BY id DESC LIMIT 500′; return $args ? $wpdb->get_results($wpdb->prepare($sql,$args)) : $wpdb->get_results($sql); } private function stats() { global $wpdb; return [ ‘all’=>(int)$wpdb->get_var(“SELECT COUNT(*) FROM {$this->table}”), ‘pending’=>(int)$wpdb->get_var(“SELECT COUNT(*) FROM {$this->table} WHERE payment_status=’pending'”), ‘waiting’=>(int)$wpdb->get_var(“SELECT COUNT(*) FROM {$this->table} WHERE payment_status=’waiting_verification'”), ‘paid’=>(int)$wpdb->get_var(“SELECT COUNT(*) FROM {$this->table} WHERE payment_status=’paid'”), ‘revenue’=>(float)$wpdb->get_var(“SELECT COALESCE(SUM(amount),0) FROM {$this->table} WHERE payment_status=’paid'”), ]; } public function dashboard_page() { if (!current_user_can(‘manage_options’)) return; $rows=$this->get_rows(); $stats=$this->stats(); $base=admin_url(‘admin.php?page=geis-payment-dashboard’); ?>

GEIS Payment Dashboard

Pendaftaran bisnis, verifikasi pembayaran manual, dan riwayat transaksi.

Total Pendaftar
Menunggu Bayar
Perlu Verifikasi
Sudah Lunas
Total Pembayaran LunasRp
‘Menunggu Bayar’,’waiting_verification’=>’Perlu Verifikasi’,’paid’=>’Lunas’,’cancelled’=>’Dibatalkan’] as $k=>$v): ?>