admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'wooaapanel_admin' ),
] );
}
// ── Pages ────────────────────────────────────────────────────────────────
public function page_dashboard(): void {
echo '
' . esc_html__( 'WC Product ↔ Server Linking', 'wooaapanel' ) . '
';
echo '
' . esc_html__( 'Link a WooCommerce product to an aaPanel server. When a customer purchases the product, a site and database will be automatically provisioned on the linked server.', 'wooaapanel' ) . '
';
echo '
';
}
// ── Helpers ───────────────────────────────────────────────────────────────
private function verify_admin(): void {
check_ajax_referer( 'wooaapanel_admin', 'nonce' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error( 'Insufficient permissions.', 403 );
}
}
private function get_server( int $id ): ?object {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wooaapanel_servers WHERE id = %d",
$id
) );
}
private function api( int $server_id ): WooAApanel_API {
$server = $this->get_server( $server_id );
if ( ! $server ) {
wp_send_json_error( 'Server not found.', 404 );
}
return WooAApanel_API::from_server( $server );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Servers
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_servers_list(): void {
$this->verify_admin();
global $wpdb;
$rows = $wpdb->get_results( "SELECT id, name, url, active, created_at FROM {$wpdb->prefix}wooaapanel_servers ORDER BY id DESC" );
wp_send_json_success( $rows );
}
public function ajax_wooaapanel_server_save(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
$name = sanitize_text_field( $_POST['name'] ?? '' );
$url = esc_url_raw( $_POST['url'] ?? '' );
$api_key = sanitize_text_field( $_POST['api_key'] ?? '' );
$active = absint( $_POST['active'] ?? 1 );
if ( ! $name || ! $url || ! $api_key ) {
wp_send_json_error( 'Name, URL and API key are required.' );
}
global $wpdb;
$data = compact( 'name', 'url', 'api_key', 'active' );
if ( $id ) {
$wpdb->update( "{$wpdb->prefix}wooaapanel_servers", $data, [ 'id' => $id ] );
} else {
$wpdb->insert( "{$wpdb->prefix}wooaapanel_servers", $data );
$id = $wpdb->insert_id;
}
wp_send_json_success( [ 'id' => $id ] );
}
public function ajax_wooaapanel_server_delete(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
global $wpdb;
$wpdb->delete( "{$wpdb->prefix}wooaapanel_servers", [ 'id' => $id ] );
wp_send_json_success();
}
public function ajax_wooaapanel_server_test(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
$api = $this->api( $id );
$res = $api->test_connection();
wp_send_json( $res );
}
// ── Remote site/db lists (used by assignment UI) ──────────────────────
public function ajax_wooaapanel_remote_sites(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
$res = $api->get_sites( 1, 200 );
wp_send_json( $res );
}
public function ajax_wooaapanel_remote_dbs(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
$res = $api->get_databases( 1, 200 );
wp_send_json( $res );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Site Assignments
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_site_assignments_list(): void {
$this->verify_admin();
global $wpdb;
$rows = $wpdb->get_results( "
SELECT a.id, a.customer_id, a.server_id, a.site_name, a.domain, a.created_at,
s.name AS server_name,
u.display_name AS customer_name, u.user_email AS customer_email
FROM {$wpdb->prefix}wooaapanel_site_assignments a
JOIN {$wpdb->prefix}wooaapanel_servers s ON s.id = a.server_id
LEFT JOIN {$wpdb->users} u ON u.ID = a.customer_id
ORDER BY a.id DESC
" );
wp_send_json_success( $rows );
}
public function ajax_wooaapanel_site_assignment_save(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
$customer_id = absint( $_POST['customer_id'] ?? 0 );
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$domain = sanitize_text_field( $_POST['domain'] ?? '' );
if ( ! $customer_id || ! $server_id || ! $site_name ) {
wp_send_json_error( 'Customer, server and site name are required.' );
}
global $wpdb;
$data = compact( 'customer_id', 'server_id', 'site_name', 'domain' );
if ( $id ) {
$wpdb->update( "{$wpdb->prefix}wooaapanel_site_assignments", $data, [ 'id' => $id ] );
} else {
$wpdb->insert( "{$wpdb->prefix}wooaapanel_site_assignments", $data );
$id = $wpdb->insert_id;
}
wp_send_json_success( [ 'id' => $id ] );
}
public function ajax_wooaapanel_site_assignment_delete(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
global $wpdb;
$wpdb->delete( "{$wpdb->prefix}wooaapanel_site_assignments", [ 'id' => $id ] );
wp_send_json_success();
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: DB Assignments
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_db_assignments_list(): void {
$this->verify_admin();
global $wpdb;
$rows = $wpdb->get_results( "
SELECT a.id, a.customer_id, a.server_id, a.db_name, a.created_at,
s.name AS server_name,
u.display_name AS customer_name, u.user_email AS customer_email
FROM {$wpdb->prefix}wooaapanel_db_assignments a
JOIN {$wpdb->prefix}wooaapanel_servers s ON s.id = a.server_id
LEFT JOIN {$wpdb->users} u ON u.ID = a.customer_id
ORDER BY a.id DESC
" );
wp_send_json_success( $rows );
}
public function ajax_wooaapanel_db_assignment_save(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
$customer_id = absint( $_POST['customer_id'] ?? 0 );
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
if ( ! $customer_id || ! $server_id || ! $db_name ) {
wp_send_json_error( 'Customer, server and database name are required.' );
}
global $wpdb;
$data = compact( 'customer_id', 'server_id', 'db_name' );
if ( $id ) {
$wpdb->update( "{$wpdb->prefix}wooaapanel_db_assignments", $data, [ 'id' => $id ] );
} else {
$wpdb->insert( "{$wpdb->prefix}wooaapanel_db_assignments", $data );
$id = $wpdb->insert_id;
}
wp_send_json_success( [ 'id' => $id ] );
}
public function ajax_wooaapanel_db_assignment_delete(): void {
$this->verify_admin();
$id = absint( $_POST['id'] ?? 0 );
global $wpdb;
$wpdb->delete( "{$wpdb->prefix}wooaapanel_db_assignments", [ 'id' => $id ] );
wp_send_json_success();
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Customer search
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_customers_search(): void {
$this->verify_admin();
$q = sanitize_text_field( $_POST['q'] ?? '' );
$users = get_users( [
'role__in' => [ 'customer', 'subscriber', 'administrator' ],
'search' => '*' . $q . '*',
'number' => 20,
'fields' => [ 'ID', 'display_name', 'user_email' ],
] );
wp_send_json_success( array_map( fn( $u ) => [
'id' => $u->ID,
'label' => $u->display_name . ' <' . $u->user_email . '>',
], $users ) );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Admin site actions (ALL operations)
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_admin_site_list(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$search = sanitize_text_field( $_POST['search'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_sites( 1, 100, $search ) );
}
public function ajax_wooaapanel_admin_site_add(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
$data = [
'webname' => sanitize_text_field( $_POST['webname'] ?? '' ),
'path' => sanitize_text_field( $_POST['path'] ?? '' ),
'type_id' => absint( $_POST['type_id'] ?? 0 ),
'version' => sanitize_text_field( $_POST['version'] ?? '' ),
'port' => absint( $_POST['port'] ?? 80 ),
'ps' => sanitize_text_field( $_POST['ps'] ?? '' ),
'ftp_username' => sanitize_text_field( $_POST['ftp_username'] ?? '' ),
'ftp_password' => sanitize_text_field( $_POST['ftp_password'] ?? '' ),
'sql' => sanitize_text_field( $_POST['sql'] ?? '' ),
'codeing' => sanitize_text_field( $_POST['codeing'] ?? 'utf8mb4' ),
'datauser' => sanitize_text_field( $_POST['datauser'] ?? '' ),
'datapassword' => sanitize_text_field( $_POST['datapassword'] ?? '' ),
];
wp_send_json( $api->add_site( $data ) );
}
public function ajax_wooaapanel_admin_site_delete(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$ftp = ! empty( $_POST['ftp'] );
$database = ! empty( $_POST['database'] );
$path = ! empty( $_POST['path'] );
$api = $this->api( $server_id );
wp_send_json( $api->delete_site( $site_name, $ftp, $database, $path ) );
}
public function ajax_wooaapanel_admin_site_domains(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_site_domains( $site_name ) );
}
public function ajax_wooaapanel_admin_site_add_domain(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$domain = sanitize_text_field( $_POST['domain'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->add_domain( $site_name, $domain ) );
}
public function ajax_wooaapanel_admin_site_del_domain(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$domain = sanitize_text_field( $_POST['domain'] ?? '' );
$site_id = absint( $_POST['site_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->delete_domain( $site_name, $domain, $site_id ) );
}
public function ajax_wooaapanel_admin_site_xss_get(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$site_path = sanitize_text_field( $_POST['site_path'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_xss( $site_name, $site_path ) );
}
public function ajax_wooaapanel_admin_site_xss_set(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$site_path = sanitize_text_field( $_POST['site_path'] ?? '' );
$enable = ! empty( $_POST['enable'] );
$api = $this->api( $server_id );
wp_send_json( $api->set_xss( $site_name, $site_path, $enable ) );
}
public function ajax_wooaapanel_admin_site_php_get(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_site_php_version( $site_name ) );
}
public function ajax_wooaapanel_admin_site_php_versions(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->get_php_versions() );
}
public function ajax_wooaapanel_admin_site_php_set(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$version = sanitize_text_field( $_POST['version'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->set_site_php_version( $site_name, $version ) );
}
public function ajax_wooaapanel_admin_site_rewrite_list(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_rewrite_list( $site_name ) );
}
public function ajax_wooaapanel_admin_site_rewrite_get(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$template = sanitize_text_field( $_POST['template'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_rewrite_content( $site_name, $template ) );
}
public function ajax_wooaapanel_admin_site_rewrite_set(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$content = wp_unslash( $_POST['content'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->set_rewrite( $site_name, $content ) );
}
public function ajax_wooaapanel_admin_site_ssl_get(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_ssl( $site_name ) );
}
public function ajax_wooaapanel_admin_site_ssl_close(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->close_ssl( $site_name ) );
}
public function ajax_wooaapanel_admin_site_ssl_list(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->list_ssl_certs() );
}
public function ajax_wooaapanel_admin_site_ssl_upload(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$key = wp_unslash( $_POST['key'] ?? '' );
$cert = wp_unslash( $_POST['cert'] ?? '' );
$domain = sanitize_text_field( $_POST['domain'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->upload_cert( $key, $cert, $domain ) );
}
public function ajax_wooaapanel_admin_site_ssl_deploy(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$cert_id = absint( $_POST['cert_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->deploy_cert_to_site( $site_name, $cert_id ) );
}
public function ajax_wooaapanel_admin_site_run_path(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$run_path = sanitize_text_field( $_POST['run_path'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->set_run_path( $site_name, $run_path ) );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Admin DB actions (ALL operations)
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_admin_db_list(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$search = sanitize_text_field( $_POST['search'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_databases( 1, 100, $search ) );
}
public function ajax_wooaapanel_admin_db_add(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$db_user = sanitize_text_field( $_POST['db_user'] ?? '' );
$password = sanitize_text_field( $_POST['password'] ?? '' );
$codeing = sanitize_text_field( $_POST['codeing'] ?? 'utf8mb4' );
$api = $this->api( $server_id );
wp_send_json( $api->add_database( $db_name, $db_user, $password, $codeing ) );
}
public function ajax_wooaapanel_admin_db_delete(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->delete_database( $db_name ) );
}
public function ajax_wooaapanel_admin_db_backup(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->backup_database( $db_name ) );
}
public function ajax_wooaapanel_admin_db_backups(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_db_backups( $db_name ) );
}
public function ajax_wooaapanel_admin_db_backup_delete(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$backup_id = absint( $_POST['backup_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->delete_db_backup( $backup_id, $db_name ) );
}
public function ajax_wooaapanel_admin_db_optimize(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->optimize_table( $db_name ) );
}
public function ajax_wooaapanel_admin_db_repair(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->repair_table( $db_name ) );
}
public function ajax_wooaapanel_admin_db_access_get(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->get_db_access( $db_name ) );
}
public function ajax_wooaapanel_admin_db_access_set(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$access = sanitize_text_field( $_POST['access'] ?? '%' );
$api = $this->api( $server_id );
wp_send_json( $api->set_db_access( $db_name, $access ) );
}
public function ajax_wooaapanel_admin_db_password(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$db_user = sanitize_text_field( $_POST['db_user'] ?? '' );
$password = sanitize_text_field( $_POST['password'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->reset_db_password( $db_name, $db_user, $password ) );
}
public function ajax_wooaapanel_admin_db_recycle(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->get_recycle_bin() );
}
public function ajax_wooaapanel_admin_db_restore(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$path = sanitize_text_field( $_POST['path'] ?? '' );
$api = $this->api( $server_id );
wp_send_json( $api->restore_from_recycle( $path ) );
}
public function ajax_wooaapanel_admin_db_sync(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->sync_to_databases() );
}
public function ajax_wooaapanel_admin_db_quota(): void {
$this->verify_admin();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$quota_mb = absint( $_POST['quota_mb'] ?? 0 );
$api = $this->api( $server_id );
wp_send_json( $api->modify_db_quota( $db_name, $quota_mb ) );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: WC Product server linking
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_products_list(): void {
$this->verify_admin();
$products = wc_get_products( [ 'limit' => 200, 'status' => 'publish' ] );
$servers = $this->get_all_servers();
$rows = [];
foreach ( $products as $product ) {
$rows[] = [
'id' => $product->get_id(),
'name' => $product->get_name(),
'server_id' => (int) get_post_meta( $product->get_id(), '_wooaapanel_server_id', true ),
];
}
wp_send_json_success( [
'products' => $rows,
'servers' => $servers,
] );
}
public function ajax_wooaapanel_product_server_save(): void {
$this->verify_admin();
$product_id = absint( $_POST['product_id'] ?? 0 );
$server_id = absint( $_POST['server_id'] ?? 0 );
update_post_meta( $product_id, '_wooaapanel_server_id', $server_id );
wp_send_json_success();
}
// ── Internal helpers ──────────────────────────────────────────────────
private function get_all_servers(): array {
global $wpdb;
return $wpdb->get_results( "SELECT id, name FROM {$wpdb->prefix}wooaapanel_servers WHERE active = 1 ORDER BY name" );
}
}