Files
WooAApanel/includes/class-wooaapanel-account.php
Malin 8bb96b9048 feat: initial WooAApanel plugin
Full WooCommerce plugin for aaPanel hosting management:
- aaPanel API client (all website + database endpoints)
- Admin: server management, site/DB assignments, full site/DB management panels
- Customer My Account: web hosting tab with sites and databases
- WooDomains PowerDNS integration for DNS management
- WooCommerce order auto-provisioning (product → server linking)
- Permission model: admin has all actions, customers have scoped access

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 12:48:06 +01:00

551 lines
26 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* WooAApanel Account WooCommerce My Account integration.
*
* Adds a "Web Hosting" tab where customers can manage their assigned sites
* and databases. DNS management is provided via WooDomains PowerDNS if
* that plugin is active.
*/
defined( 'ABSPATH' ) || exit;
class WooAApanel_Account {
const ENDPOINT = 'web-hosting';
public function __construct() {
add_action( 'init', [ $this, 'register_endpoint' ] );
add_filter( 'woocommerce_account_menu_items', [ $this, 'add_menu_item' ] );
add_action( 'woocommerce_account_' . self::ENDPOINT . '_endpoint', [ $this, 'render_page' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
$actions = [
// Sites
'wooaapanel_acct_sites',
'wooaapanel_acct_site_domains',
'wooaapanel_acct_site_add_domain',
'wooaapanel_acct_site_del_domain',
'wooaapanel_acct_site_xss_get',
'wooaapanel_acct_site_xss_set',
'wooaapanel_acct_site_php_get',
'wooaapanel_acct_site_php_versions',
'wooaapanel_acct_site_php_set',
'wooaapanel_acct_site_rewrite_get',
'wooaapanel_acct_site_rewrite_set',
'wooaapanel_acct_site_ssl_get',
'wooaapanel_acct_server_info',
// Databases
'wooaapanel_acct_dbs',
'wooaapanel_acct_db_backup',
'wooaapanel_acct_db_backups',
'wooaapanel_acct_db_backup_delete',
'wooaapanel_acct_db_optimize',
'wooaapanel_acct_db_repair',
'wooaapanel_acct_db_password',
];
foreach ( $actions as $action ) {
add_action( 'wp_ajax_' . $action, [ $this, 'ajax_' . $action ] );
}
}
public function register_endpoint(): void {
add_rewrite_endpoint( self::ENDPOINT, EP_ROOT | EP_PAGES );
}
public function add_menu_item( array $items ): array {
$logout = $items['customer-logout'] ?? null;
unset( $items['customer-logout'] );
$items[ self::ENDPOINT ] = __( 'Web Hosting', 'wooaapanel' );
if ( $logout ) {
$items['customer-logout'] = $logout;
}
return $items;
}
public function enqueue_assets(): void {
if ( ! is_account_page() ) {
return;
}
wp_enqueue_style( 'wooaapanel-account', WOOAAPANEL_PLUGIN_URL . 'assets/css/wooaapanel-account.css', [], WOOAAPANEL_VERSION );
wp_enqueue_script( 'wooaapanel-account', WOOAAPANEL_PLUGIN_URL . 'assets/js/wooaapanel-account.js', [ 'jquery' ], WOOAAPANEL_VERSION, true );
wp_localize_script( 'wooaapanel-account', 'wooaapanelAcct', [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'wooaapanel_account' ),
'pdns_nonce' => class_exists( 'WooDomains_PowerDNS_API' ) ? wp_create_nonce( 'woodomains_nonce' ) : '',
'pdns_active' => class_exists( 'WooDomains_PowerDNS_API' ) ? 1 : 0,
'ajax_url_woodomains' => admin_url( 'admin-ajax.php' ),
] );
}
// ── My Account page render ────────────────────────────────────────────────
public function render_page(): void {
if ( ! is_user_logged_in() ) {
echo '<p>' . esc_html__( 'Please log in to manage your hosting.', 'wooaapanel' ) . '</p>';
return;
}
$customer_id = get_current_user_id();
$site_assigns = $this->get_site_assignments( $customer_id );
$db_assigns = $this->get_db_assignments( $customer_id );
$pdns_active = class_exists( 'WooDomains_PowerDNS_API' );
if ( empty( $site_assigns ) && empty( $db_assigns ) ) {
echo '<div class="woocommerce-info">' . esc_html__( 'You have no hosting resources assigned yet. Please contact support.', 'wooaapanel' ) . '</div>';
return;
}
?>
<div class="wooaapanel-account" id="wooaapanel-account">
<div id="wap-acct-notices"></div>
<?php if ( ! empty( $site_assigns ) ) : ?>
<h2><?php esc_html_e( 'Websites', 'wooaapanel' ); ?></h2>
<?php foreach ( $site_assigns as $assign ) : ?>
<div class="wap-site-panel"
data-assignment-id="<?php echo esc_attr( $assign->id ); ?>"
data-server-id="<?php echo esc_attr( $assign->server_id ); ?>"
data-site-name="<?php echo esc_attr( $assign->site_name ); ?>"
data-domain="<?php echo esc_attr( $assign->domain ); ?>">
<div class="wap-panel-header">
<span class="wap-site-name"><?php echo esc_html( $assign->site_name ); ?></span>
<span class="wap-domain"><?php echo esc_html( $assign->domain ); ?></span>
<span class="wap-server-label"><?php echo esc_html( $assign->server_name ); ?></span>
<div class="wap-panel-actions">
<button class="button wap-btn-sm wap-load-domains"><?php esc_html_e( 'Domains', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-load-php"><?php esc_html_e( 'PHP', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-load-rewrite"><?php esc_html_e( 'URL Rewrite', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-load-ssl"><?php esc_html_e( 'SSL', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-load-server-info"><?php esc_html_e( 'Server Info', 'wooaapanel' ); ?></button>
<?php if ( $pdns_active && $assign->domain ) : ?>
<button class="button wap-btn-sm wap-load-dns"
data-zone="<?php echo esc_attr( rtrim( $assign->domain, '.' ) . '.' ); ?>">
<?php esc_html_e( 'DNS Records', 'wooaapanel' ); ?>
</button>
<?php endif; ?>
</div>
</div><!-- .wap-panel-header -->
<!-- Domains -->
<div class="wap-section wap-domains-section" style="display:none">
<h4><?php esc_html_e( 'Domain Names', 'wooaapanel' ); ?></h4>
<div class="wap-domains-list"></div>
<div class="wap-add-domain-form">
<input type="text" class="wap-new-domain input-text" placeholder="newdomain.com">
<button class="button wap-add-domain-btn"><?php esc_html_e( 'Add Domain', 'wooaapanel' ); ?></button>
<span class="wap-domain-notice"></span>
</div>
</div>
<!-- PHP Version -->
<div class="wap-section wap-php-section" style="display:none">
<h4><?php esc_html_e( 'PHP Version', 'wooaapanel' ); ?></h4>
<div class="wap-php-current"></div>
<select class="wap-php-select"></select>
<button class="button wap-php-set-btn"><?php esc_html_e( 'Set PHP Version', 'wooaapanel' ); ?></button>
<span class="wap-php-notice"></span>
</div>
<!-- URL Rewrite -->
<div class="wap-section wap-rewrite-section" style="display:none">
<h4><?php esc_html_e( 'URL Rewrite', 'wooaapanel' ); ?></h4>
<textarea class="wap-rewrite-content" rows="10" style="width:100%;font-family:monospace"></textarea>
<button class="button wap-rewrite-save-btn"><?php esc_html_e( 'Save Rewrite', 'wooaapanel' ); ?></button>
<span class="wap-rewrite-notice"></span>
</div>
<!-- SSL Info -->
<div class="wap-section wap-ssl-section" style="display:none">
<h4><?php esc_html_e( 'SSL Certificate', 'wooaapanel' ); ?></h4>
<div class="wap-ssl-info"></div>
</div>
<!-- XSS -->
<div class="wap-section wap-xss-section" style="display:none">
<h4><?php esc_html_e( 'Anti-XSS Protection', 'wooaapanel' ); ?></h4>
<div class="wap-xss-status"></div>
<button class="button wap-xss-toggle-btn"><?php esc_html_e( 'Toggle XSS Protection', 'wooaapanel' ); ?></button>
<span class="wap-xss-notice"></span>
</div>
<!-- Server Info -->
<div class="wap-section wap-server-section" style="display:none">
<h4><?php esc_html_e( 'Server Information', 'wooaapanel' ); ?></h4>
<div class="wap-server-info"></div>
</div>
<!-- DNS (WooDomains PowerDNS integration) -->
<?php if ( $pdns_active && $assign->domain ) : ?>
<div class="wap-section wap-dns-section" style="display:none"
data-zone="<?php echo esc_attr( rtrim( $assign->domain, '.' ) . '.' ); ?>">
<h4><?php esc_html_e( 'DNS Records', 'wooaapanel' ); ?></h4>
<div class="wap-dns-records-list"></div>
<hr>
<h5><?php esc_html_e( 'Add / Update Record', 'wooaapanel' ); ?></h5>
<div class="wap-dns-add-form">
<label><?php esc_html_e( 'Name', 'wooaapanel' ); ?> <input type="text" class="wap-dns-name input-text" placeholder="<?php echo esc_attr( $assign->domain . '.' ); ?>"></label>
<label><?php esc_html_e( 'Type', 'wooaapanel' ); ?>
<select class="wap-dns-type">
<?php foreach ( [ 'A', 'AAAA', 'CNAME', 'MX', 'TXT', 'SRV', 'CAA' ] as $t ) : ?>
<option><?php echo esc_html( $t ); ?></option>
<?php endforeach; ?>
</select>
</label>
<label><?php esc_html_e( 'TTL', 'wooaapanel' ); ?> <input type="number" class="wap-dns-ttl input-text" value="3600" min="60" style="width:80px"></label>
<label><?php esc_html_e( 'Content (one per line)', 'wooaapanel' ); ?><br>
<textarea class="wap-dns-content input-text" rows="3"></textarea>
</label>
<button class="button wap-dns-save-btn"><?php esc_html_e( 'Save Record', 'wooaapanel' ); ?></button>
<span class="wap-dns-notice"></span>
</div>
</div>
<?php endif; ?>
</div><!-- .wap-site-panel -->
<?php endforeach; ?>
<?php endif; ?>
<?php if ( ! empty( $db_assigns ) ) : ?>
<h2><?php esc_html_e( 'Databases', 'wooaapanel' ); ?></h2>
<?php foreach ( $db_assigns as $assign ) : ?>
<div class="wap-db-panel"
data-assignment-id="<?php echo esc_attr( $assign->id ); ?>"
data-server-id="<?php echo esc_attr( $assign->server_id ); ?>"
data-db-name="<?php echo esc_attr( $assign->db_name ); ?>">
<div class="wap-panel-header">
<span class="wap-db-name"><strong><?php echo esc_html( $assign->db_name ); ?></strong></span>
<span class="wap-server-label"><?php echo esc_html( $assign->server_name ); ?></span>
<div class="wap-panel-actions">
<button class="button wap-btn-sm wap-db-backup-btn"><?php esc_html_e( 'Backup', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-load-db-backups"><?php esc_html_e( 'Backups', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-db-optimize-btn"><?php esc_html_e( 'Optimize', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-db-repair-btn"><?php esc_html_e( 'Repair', 'wooaapanel' ); ?></button>
<button class="button wap-btn-sm wap-db-password-btn"><?php esc_html_e( 'Change Password', 'wooaapanel' ); ?></button>
</div>
</div>
<div class="wap-db-action-notice"></div>
<!-- Backup list -->
<div class="wap-section wap-db-backups-section" style="display:none">
<h4><?php esc_html_e( 'Database Backups', 'wooaapanel' ); ?></h4>
<div class="wap-db-backups-list"></div>
</div>
<!-- Change password form -->
<div class="wap-section wap-db-password-section" style="display:none">
<h4><?php esc_html_e( 'Change Database Password', 'wooaapanel' ); ?></h4>
<input type="text" class="wap-db-user input-text" placeholder="<?php esc_attr_e( 'Database user', 'wooaapanel' ); ?>">
<input type="password" class="wap-db-new-pass input-text" placeholder="<?php esc_attr_e( 'New password', 'wooaapanel' ); ?>">
<button class="button wap-db-pass-save-btn"><?php esc_html_e( 'Save Password', 'wooaapanel' ); ?></button>
<span class="wap-db-pass-notice"></span>
</div>
</div><!-- .wap-db-panel -->
<?php endforeach; ?>
<?php endif; ?>
</div><!-- #wooaapanel-account -->
<?php
}
// ── Helpers ───────────────────────────────────────────────────────────────
private function get_site_assignments( int $customer_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare( "
SELECT a.id, a.server_id, a.site_name, a.domain,
s.name AS server_name, s.url AS server_url
FROM {$wpdb->prefix}wooaapanel_site_assignments a
JOIN {$wpdb->prefix}wooaapanel_servers s ON s.id = a.server_id
WHERE a.customer_id = %d AND s.active = 1
ORDER BY a.site_name
", $customer_id ) );
}
private function get_db_assignments( int $customer_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare( "
SELECT a.id, a.server_id, a.db_name,
s.name AS server_name
FROM {$wpdb->prefix}wooaapanel_db_assignments a
JOIN {$wpdb->prefix}wooaapanel_servers s ON s.id = a.server_id
WHERE a.customer_id = %d AND s.active = 1
ORDER BY a.db_name
", $customer_id ) );
}
private function get_server( int $id ): ?object {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wooaapanel_servers WHERE id = %d AND active = 1",
$id
) );
}
/** Verify nonce + login. */
private function account_verify(): void {
check_ajax_referer( 'wooaapanel_account', 'nonce' );
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'Not logged in.', 401 );
}
}
/** Confirm the current user owns this site assignment. */
private function verify_site_ownership( int $server_id, string $site_name ): bool {
global $wpdb;
return (bool) $wpdb->get_var( $wpdb->prepare( "
SELECT id FROM {$wpdb->prefix}wooaapanel_site_assignments
WHERE customer_id = %d AND server_id = %d AND site_name = %s
", get_current_user_id(), $server_id, $site_name ) );
}
/** Confirm the current user owns this DB assignment. */
private function verify_db_ownership( int $server_id, string $db_name ): bool {
global $wpdb;
return (bool) $wpdb->get_var( $wpdb->prepare( "
SELECT id FROM {$wpdb->prefix}wooaapanel_db_assignments
WHERE customer_id = %d AND server_id = %d AND db_name = %s
", get_current_user_id(), $server_id, $db_name ) );
}
private function api_for_site( int $server_id, string $site_name ): WooAApanel_API {
if ( ! $this->verify_site_ownership( $server_id, $site_name ) ) {
wp_send_json_error( 'Access denied.', 403 );
}
$server = $this->get_server( $server_id );
if ( ! $server ) {
wp_send_json_error( 'Server unavailable.' );
}
return WooAApanel_API::from_server( $server );
}
private function api_for_db( int $server_id, string $db_name ): WooAApanel_API {
if ( ! $this->verify_db_ownership( $server_id, $db_name ) ) {
wp_send_json_error( 'Access denied.', 403 );
}
$server = $this->get_server( $server_id );
if ( ! $server ) {
wp_send_json_error( 'Server unavailable.' );
}
return WooAApanel_API::from_server( $server );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Account Sites
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_acct_sites(): void {
$this->account_verify();
$sites = $this->get_site_assignments( get_current_user_id() );
$dbs = $this->get_db_assignments( get_current_user_id() );
wp_send_json_success( [ 'sites' => $sites, 'databases' => $dbs ] );
}
public function ajax_wooaapanel_acct_site_domains(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_site_domains( $site_name ) );
}
public function ajax_wooaapanel_acct_site_add_domain(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$domain = sanitize_text_field( $_POST['domain'] ?? '' );
if ( ! $domain ) {
wp_send_json_error( 'Domain is required.' );
}
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->add_domain( $site_name, $domain ) );
}
public function ajax_wooaapanel_acct_site_del_domain(): void {
$this->account_verify();
$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_for_site( $server_id, $site_name );
wp_send_json( $api->delete_domain( $site_name, $domain, $site_id ) );
}
public function ajax_wooaapanel_acct_site_xss_get(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$site_path = sanitize_text_field( $_POST['site_path'] ?? "/www/wwwroot/{$site_name}" );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_xss( $site_name, $site_path ) );
}
public function ajax_wooaapanel_acct_site_xss_set(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$site_path = sanitize_text_field( $_POST['site_path'] ?? "/www/wwwroot/{$site_name}" );
$enable = ! empty( $_POST['enable'] );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->set_xss( $site_name, $site_path, $enable ) );
}
public function ajax_wooaapanel_acct_site_php_get(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_site_php_version( $site_name ) );
}
public function ajax_wooaapanel_acct_site_php_versions(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_php_versions() );
}
public function ajax_wooaapanel_acct_site_php_set(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$version = sanitize_text_field( $_POST['version'] ?? '' );
if ( ! $version ) {
wp_send_json_error( 'PHP version is required.' );
}
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->set_site_php_version( $site_name, $version ) );
}
public function ajax_wooaapanel_acct_site_rewrite_get(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$template = sanitize_text_field( $_POST['template'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_rewrite_content( $site_name, $template ) );
}
public function ajax_wooaapanel_acct_site_rewrite_set(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$content = wp_unslash( $_POST['content'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->set_rewrite( $site_name, $content ) );
}
public function ajax_wooaapanel_acct_site_ssl_get(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
$api = $this->api_for_site( $server_id, $site_name );
wp_send_json( $api->get_ssl( $site_name ) );
}
public function ajax_wooaapanel_acct_server_info(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$site_name = sanitize_text_field( $_POST['site_name'] ?? '' );
// Fetch the server row to expose only safe fields (name, IP visible via panel URL host).
if ( ! $this->verify_site_ownership( $server_id, $site_name ) ) {
wp_send_json_error( 'Access denied.', 403 );
}
$server = $this->get_server( $server_id );
if ( ! $server ) {
wp_send_json_error( 'Server unavailable.' );
}
// Parse IP from URL.
$host = parse_url( $server->url, PHP_URL_HOST );
// External IP via aaPanel status endpoint.
$api = WooAApanel_API::from_server( $server );
$res = $api->get_server_info();
wp_send_json_success( [
'server_name' => $server->name,
'server_host' => $host,
'panel_url' => $server->url,
'panel_status' => $res['data'] ?? [],
] );
}
// ═════════════════════════════════════════════════════════════════════════
// AJAX: Account Databases
// ═════════════════════════════════════════════════════════════════════════
public function ajax_wooaapanel_acct_dbs(): void {
$this->account_verify();
$dbs = $this->get_db_assignments( get_current_user_id() );
wp_send_json_success( $dbs );
}
public function ajax_wooaapanel_acct_db_backup(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->backup_database( $db_name ) );
}
public function ajax_wooaapanel_acct_db_backups(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->get_db_backups( $db_name ) );
}
public function ajax_wooaapanel_acct_db_backup_delete(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$backup_id = absint( $_POST['backup_id'] ?? 0 );
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->delete_db_backup( $backup_id, $db_name ) );
}
public function ajax_wooaapanel_acct_db_optimize(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->optimize_table( $db_name ) );
}
public function ajax_wooaapanel_acct_db_repair(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->repair_table( $db_name ) );
}
public function ajax_wooaapanel_acct_db_password(): void {
$this->account_verify();
$server_id = absint( $_POST['server_id'] ?? 0 );
$db_name = sanitize_text_field( $_POST['db_name'] ?? '' );
$db_user = sanitize_text_field( $_POST['db_user'] ?? '' );
$password = $_POST['password'] ?? '';
if ( ! $db_user || ! $password ) {
wp_send_json_error( 'Database user and new password are required.' );
}
$api = $this->api_for_db( $server_id, $db_name );
wp_send_json( $api->reset_db_password( $db_name, $db_user, $password ) );
}
}