idrivee2-media-upload/includes/class-admin-page.php
2026-08-17 15:50:51 +00:00

938 lines
29 KiB
PHP

<?php
/**
* Admin Page handler for iDrivee2 Media Upload.
*
* @package iDrivee2Media
* @since 0.3.0
*/
declare(strict_types=1);
namespace iDrivee2Media;
/**
* Prevent direct access to this file.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Admin page handler for iDrivee2 Media Upload.
*
* Manages the admin interface under Settings → iDrivee2, including settings display,
* AJAX handlers for connection testing and file uploads, and script enqueuing.
*
* @since 0.3.0
*/
class Admin_Page {
/**
* Configuration instance.
*
* @var Config
*/
private $config;
/**
* S3 client factory.
*
* @var S3_Client_Factory
*/
private $client_factory;
/**
* Logger instance.
*
* @var Logger
*/
private $logger;
/**
* Rate limiter instance.
*
* @var Rate_Limiter
*/
private $rate_limiter;
/**
* Plugin file path.
*
* @var string
*/
private $plugin_file;
/**
* Constructor.
*
* @since 0.3.0
*
* @param Config $config Configuration instance.
* @param S3_Client_Factory $client_factory S3 client factory.
* @param Logger $logger Logger instance.
* @param Rate_Limiter $rate_limiter Rate limiter instance.
* @param string $plugin_file Path to the main plugin file.
*/
public function __construct( Config $config, S3_Client_Factory $client_factory, Logger $logger, Rate_Limiter $rate_limiter, string $plugin_file ) {
$this->config = $config;
$this->client_factory = $client_factory;
$this->logger = $logger;
$this->rate_limiter = $rate_limiter;
$this->plugin_file = $plugin_file;
}
/**
* Register hooks for the admin page.
*
* @since 0.3.0
*
* @return void
*/
public function register(): void {
add_action( 'admin_menu', array( $this, 'register_settings_page' ), 20 );
add_action( 'admin_init', array( $this, 'register_settings' ) );
add_action( 'admin_init', array( $this, 'handle_test_actions' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ), 20 );
}
/**
* Register the iDrivee2 settings page under the Settings menu.
*
* Adds a submenu page to the Settings section of the admin where users
* can configure and test their iDrivee2 setup.
*
* @since 0.3.0
*
* @return void
*/
public function register_settings_page(): void {
add_options_page(
/* translators: Admin menu title. */
__( 'iDrivee2 Media Upload Settings', 'idrivee2-media-upload' ),
/* translators: Admin menu label. */
__( 'iDrivee2', 'idrivee2-media-upload' ),
'manage_options',
'idrivee2-media-upload',
array( $this, 'render_settings_page' )
);
}
/**
* Register settings with WordPress Settings API.
*
* @since 0.3.0
*
* @return void
*/
public function register_settings(): void {
register_setting(
'idrivee2_media_settings_group',
'idrivee2_media_settings',
array(
'sanitize_callback' => array( $this, 'sanitize_settings' ),
)
);
}
/**
* Handle test action POST requests.
*
* Processes test connection, upload test file, and delete test file actions.
*
* @since 0.3.0
*
* @return void
*/
public function handle_test_actions(): void {
// Only process on settings page.
$current_page = isset( $_GET['page'] ) && is_string( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
if ( 'idrivee2-media-upload' !== $current_page ) {
return;
}
// Handle test connection.
if ( isset( $_POST['idrivee2_test_connection'] ) ) {
check_admin_referer( 'idrivee2_test_connection' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'idrivee2-media-upload' ) );
}
$this->handle_test_connection();
return;
}
// Handle upload test file.
if ( isset( $_POST['idrivee2_upload_test'] ) ) {
check_admin_referer( 'idrivee2_upload_test' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'idrivee2-media-upload' ) );
}
$this->handle_upload_test();
return;
}
// Handle delete test file.
if ( isset( $_POST['idrivee2_delete_test'] ) && isset( $_POST['test_file'] ) ) {
check_admin_referer( 'idrivee2_delete_test' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'idrivee2-media-upload' ) );
}
$raw_test_file = is_string( $_POST['test_file'] ) ? wp_unslash( $_POST['test_file'] ) : '';
$this->handle_delete_test( sanitize_file_name( $raw_test_file ) );
return;
}
}
/**
* Handle test connection action.
*
* @since 0.3.0
*
* @return void
*/
private function handle_test_connection(): void {
// Check rate limit.
if ( $this->rate_limiter->is_rate_limited( 'test_connection', 60 ) ) {
$remaining = $this->rate_limiter->get_remaining_time( 'test_connection', 60 );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %d is the number of seconds to wait. */
__( 'Please wait %d seconds before testing again.', 'idrivee2-media-upload' ),
$remaining
),
),
30
);
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
if ( ! $this->config->is_configured() ) {
$this->logger->warning( 'Test connection attempted with incomplete configuration' );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => __( 'Configuration is incomplete. Please check your settings.', 'idrivee2-media-upload' ),
),
30
);
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
// Record this action for rate limiting.
$this->rate_limiter->record_action( 'test_connection', 60 );
try {
$client = $this->client_factory->create();
$client->headBucket( array( 'Bucket' => $this->config->get_bucket() ) );
$this->logger->s3_operation( 'headBucket', true );
set_transient(
'idrivee2_test_result',
array(
'type' => 'success',
'message' => __( 'Connection successful! Your S3 configuration is working correctly.', 'idrivee2-media-upload' ),
),
30
);
} catch ( \Aws\Exception\AwsException $e ) {
$this->logger->s3_operation( 'headBucket', false, '', $e->getAwsErrorMessage() ?? '' );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message from AWS. */
__( 'AWS Error: %s', 'idrivee2-media-upload' ),
$e->getAwsErrorMessage() ?? __( 'Unknown error', 'idrivee2-media-upload' )
),
),
30
);
} catch ( \Exception $e ) {
$this->logger->error( 'Test connection failed: ' . $e->getMessage() );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message. */
__( 'Error: %s', 'idrivee2-media-upload' ),
$e->getMessage()
),
),
30
);
}
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
/**
* Handle upload test file action.
*
* @since 0.3.0
*
* @return void
*/
private function handle_upload_test(): void {
// Check rate limit.
if ( $this->rate_limiter->is_rate_limited( 'upload_test', 60 ) ) {
$remaining = $this->rate_limiter->get_remaining_time( 'upload_test', 60 );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %d is the number of seconds to wait. */
__( 'Please wait %d seconds before uploading again.', 'idrivee2-media-upload' ),
$remaining
),
),
30
);
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
// Record this action for rate limiting.
$this->rate_limiter->record_action( 'upload_test', 60 );
try {
// Generate timestamp for filename (YYYYMMDDHHMMSS).
$timestamp = gmdate( 'YmdHis' );
$file_name = 'test-' . $timestamp . '.txt';
// Create file content.
$content = 'Test file uploaded at ' . gmdate( 'Y-m-d H:i:s' ) . ' UTC';
// Initialize the S3 client.
$client = $this->client_factory->create();
// Upload to S3.
$result = $client->putObject(
array(
'Bucket' => $this->config->get_bucket(),
'Key' => $file_name,
'Body' => $content,
// ACL matches the media uploader: files are served publicly via CDN/S3.
'ACL' => 'public-read',
)
);
// Log successful upload.
$this->logger->s3_operation( 'putObject', true, $file_name );
// Get the public URL - use CDN domain if configured, otherwise S3 ObjectURL.
$s3_object_url = isset( $result['ObjectURL'] ) && is_string( $result['ObjectURL'] ) ? $result['ObjectURL'] : '';
$object_url = $this->get_public_url( $file_name, $s3_object_url );
set_transient(
'idrivee2_test_result',
array(
'type' => 'success',
'message' => __( 'File uploaded successfully!', 'idrivee2-media-upload' ),
'file_name' => $file_name,
'object_url' => $object_url,
),
30
);
} catch ( \Aws\Exception\AwsException $e ) {
$this->logger->s3_operation( 'putObject', false, $file_name, $e->getAwsErrorMessage() ?? '' );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message from AWS. */
__( 'AWS Error: %s', 'idrivee2-media-upload' ),
$e->getAwsErrorMessage() ?? __( 'Unknown error', 'idrivee2-media-upload' )
),
),
30
);
} catch ( \Exception $e ) {
$this->logger->error( 'Test upload failed: ' . $e->getMessage() );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message. */
__( 'Error: %s', 'idrivee2-media-upload' ),
$e->getMessage()
),
),
30
);
}
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
/**
* Get the public URL for an uploaded file.
*
* Uses CDN domain if configured, otherwise falls back to S3 ObjectURL.
*
* @since 0.3.0
*
* @param string $file_name The file name/key in S3.
* @param string $object_url The S3 ObjectURL returned by AWS SDK.
* @return string The public URL to access the file.
*/
private function get_public_url( string $file_name, string $object_url ): string {
// If custom domain is configured, use it.
if ( $this->config->has_domain() ) {
return trailingslashit( $this->config->get_domain() ) . $file_name;
}
// Otherwise, use the S3 ObjectURL.
return $object_url;
}
/**
* Handle delete test file action.
*
* @since 0.3.0
*
* @param string $file_name The test file name to delete.
* @return void
*/
private function handle_delete_test( string $file_name ): void {
// Validate file name pattern (must be test-YYYYMMDDHHMMSS.txt).
if ( ! preg_match( '/^test-\d{14}\.txt$/', $file_name ) ) {
$this->logger->warning( 'Invalid test file name format attempted: ' . $file_name );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => __( 'Invalid test file name format.', 'idrivee2-media-upload' ),
),
30
);
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
try {
// Initialize the S3 client.
$client = $this->client_factory->create();
// Delete object from S3.
$client->deleteObject(
array(
'Bucket' => $this->config->get_bucket(),
'Key' => $file_name,
)
);
// Log successful deletion.
$this->logger->s3_operation( 'deleteObject', true, $file_name );
set_transient(
'idrivee2_test_result',
array(
'type' => 'info',
'message' => sprintf(
/* translators: %s is the file name. */
__( 'File %s deleted successfully.', 'idrivee2-media-upload' ),
'<code>' . esc_html( $file_name ) . '</code>'
),
),
30
);
} catch ( \Aws\Exception\AwsException $e ) {
$this->logger->s3_operation( 'deleteObject', false, $file_name, $e->getAwsErrorMessage() ?? '' );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message from AWS. */
__( 'AWS Error: %s', 'idrivee2-media-upload' ),
$e->getAwsErrorMessage() ?? __( 'Unknown error', 'idrivee2-media-upload' )
),
),
30
);
} catch ( \Exception $e ) {
$this->logger->error( 'Test file deletion failed: ' . $e->getMessage() );
set_transient(
'idrivee2_test_result',
array(
'type' => 'error',
'message' => sprintf(
/* translators: %s is the error message. */
__( 'Error: %s', 'idrivee2-media-upload' ),
$e->getMessage()
),
),
30
);
}
wp_safe_redirect( admin_url( 'options-general.php?page=idrivee2-media-upload' ) );
exit;
}
/**
* Sanitize settings before saving.
*
* @since 0.3.0
*
* @param array<string, string> $input Input settings.
* @return array<string, string> Sanitized settings.
*/
public function sanitize_settings( array $input ): array {
$sanitized = array();
// Sanitize host.
if ( isset( $input['host'] ) ) {
$sanitized['host'] = sanitize_text_field( $input['host'] );
// Validate that host starts with https://.
if ( ! empty( $sanitized['host'] ) && ! str_starts_with( $sanitized['host'], 'https://' ) ) {
add_settings_error(
'idrivee2_media_settings',
'invalid_host',
__( 'Host URL must start with "https://".', 'idrivee2-media-upload' )
);
}
}
// Sanitize other fields.
$sanitized['key'] = isset( $input['key'] ) ? sanitize_text_field( $input['key'] ) : '';
$sanitized['secret'] = isset( $input['secret'] ) ? sanitize_text_field( $input['secret'] ) : '';
$sanitized['bucket'] = isset( $input['bucket'] ) ? sanitize_text_field( $input['bucket'] ) : '';
$sanitized['region'] = isset( $input['region'] ) ? sanitize_text_field( $input['region'] ) : '';
$sanitized['domain'] = isset( $input['domain'] ) ? sanitize_text_field( $input['domain'] ) : '';
// Sub-sizes mode: strict whitelist, default 'all'.
$raw_mode = isset( $input['subsizes_mode'] ) ? strtolower( (string) sanitize_text_field( $input['subsizes_mode'] ) ) : '';
$allowed_modes = array( 'all', 'thumbnail', 'none' );
$sanitized['subsizes_mode'] = in_array( $raw_mode, $allowed_modes, true ) ? $raw_mode : 'all';
// Data cleanup on uninstall: checkbox, default off (preserve data).
$sanitized['delete_on_uninstall'] = ! empty( $input['delete_on_uninstall'] ) ? '1' : '';
return $sanitized;
}
/**
* Enqueue the admin JavaScript for enhanced UX.
*
* Loads the iDrivee2 admin script on the Settings → iDrivee2 page.
*
* @since 0.3.0
*
* @param string $hook The current admin page hook suffix.
* @return void
*/
public function enqueue_admin_scripts( string $hook ): void {
// Only load script on our settings page.
if ( 'settings_page_idrivee2-media-upload' !== $hook ) {
return;
}
wp_enqueue_script(
'idrivee2-media-admin',
plugin_dir_url( $this->plugin_file ) . 'assets/js/admin.js',
array( 'jquery' ),
defined( 'IDRIVEE2_MEDIA_VERSION' ) ? IDRIVEE2_MEDIA_VERSION : '1.0.0',
true
);
}
/**
* Render the iDrivee2 Media Upload settings page.
*
* Displays configuration form with fields for S3 settings. Fields are
* read-only if values are defined in wp-config.php.
*
* @since 0.3.0
*
* @return void
*/
public function render_settings_page(): void {
$host = $this->config->get_host();
$access_key = $this->config->get_key();
$secret = $this->config->get_secret();
$bucket = $this->config->get_bucket();
$region = $this->config->get_region();
$domain = $this->config->get_domain();
$subsizes_mode = $this->config->get_subsizes_mode();
$delete_on_uninstall = $this->config->is_delete_on_uninstall();
$is_configured = $this->config->is_configured();
// Check which fields are defined in wp-config.php.
$host_in_config = $this->config->is_defined_in_wp_config( 'host' );
$key_in_config = $this->config->is_defined_in_wp_config( 'key' );
$secret_in_config = $this->config->is_defined_in_wp_config( 'secret' );
$bucket_in_config = $this->config->is_defined_in_wp_config( 'bucket' );
$region_in_config = $this->config->is_defined_in_wp_config( 'region' );
$domain_in_config = $this->config->is_defined_in_wp_config( 'domain' );
$subsizes_mode_in_config = $this->config->is_defined_in_wp_config( 'subsizes_mode' );
$any_in_config = $host_in_config || $key_in_config || $secret_in_config || $bucket_in_config || $region_in_config || $domain_in_config || $subsizes_mode_in_config;
?>
<div class="wrap">
<h1><?php esc_html_e( 'iDrivee2 Media Upload Settings', 'idrivee2-media-upload' ); ?></h1>
<?php settings_errors(); ?>
<?php Manager_Dependency::render_settings_notice(); ?>
<?php if ( $any_in_config ) : ?>
<div class="notice notice-info">
<p><?php esc_html_e( 'Some settings are defined in wp-config.php and cannot be changed here. These fields are shown as read-only.', 'idrivee2-media-upload' ); ?></p>
</div>
<?php endif; ?>
<form method="post" action="options.php">
<?php settings_fields( 'idrivee2_media_settings_group' ); ?>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row">
<label for="idrivee2_host"><?php esc_html_e( 'S3 Host', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="url"
id="idrivee2_host"
name="idrivee2_media_settings[host]"
value="<?php echo esc_attr( $host ); ?>"
class="regular-text"
<?php echo $host_in_config ? 'readonly' : ''; ?>
<?php echo ! $host_in_config ? 'required' : ''; ?>
/>
<p class="description">
<?php
if ( $host_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_HOST)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'S3-compatible endpoint URL. Must start with "https://".', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_key"><?php esc_html_e( 'Access Key ID', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="text"
id="idrivee2_key"
name="idrivee2_media_settings[key]"
value="<?php echo esc_attr( $access_key ); ?>"
class="regular-text"
<?php echo $key_in_config ? 'readonly' : ''; ?>
<?php echo ! $key_in_config ? 'required' : ''; ?>
/>
<p class="description">
<?php
if ( $key_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_KEY)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'Your S3 access key ID.', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_secret"><?php esc_html_e( 'Secret Access Key', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="password"
id="idrivee2_secret"
name="idrivee2_media_settings[secret]"
value="<?php echo esc_attr( $secret ); ?>"
class="regular-text"
<?php echo $secret_in_config ? 'readonly' : ''; ?>
<?php echo ! $secret_in_config ? 'required' : ''; ?>
/>
<p class="description">
<?php
if ( $secret_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_SECRET)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'Your S3 secret access key.', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_bucket"><?php esc_html_e( 'Bucket Name', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="text"
id="idrivee2_bucket"
name="idrivee2_media_settings[bucket]"
value="<?php echo esc_attr( $bucket ); ?>"
class="regular-text"
<?php echo $bucket_in_config ? 'readonly' : ''; ?>
<?php echo ! $bucket_in_config ? 'required' : ''; ?>
/>
<p class="description">
<?php
if ( $bucket_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_BUCKET)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'The name of your S3 bucket.', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_region"><?php esc_html_e( 'Region', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="text"
id="idrivee2_region"
name="idrivee2_media_settings[region]"
value="<?php echo esc_attr( $region ); ?>"
class="regular-text"
placeholder="us-east-1"
<?php echo $region_in_config ? 'readonly' : ''; ?>
<?php echo ! $region_in_config ? 'required' : ''; ?>
/>
<p class="description">
<?php
if ( $region_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_REGION)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'AWS region (e.g., us-east-1, eu-west-1).', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_domain"><?php esc_html_e( 'Custom CDN Domain', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<input
type="url"
id="idrivee2_domain"
name="idrivee2_media_settings[domain]"
value="<?php echo esc_attr( $domain ); ?>"
class="regular-text"
placeholder="https://cdn.example.com"
<?php echo $domain_in_config ? 'readonly' : ''; ?>
/>
<p class="description">
<?php
if ( $domain_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_DOMAIN)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'Optional: Custom domain for serving media files.', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="idrivee2_subsizes_mode"><?php esc_html_e( 'Image Sub-sizes', 'idrivee2-media-upload' ); ?></label>
</th>
<td>
<select
id="idrivee2_subsizes_mode"
name="idrivee2_media_settings[subsizes_mode]"
<?php echo $subsizes_mode_in_config ? 'disabled' : ''; ?>
>
<?php
$mode_options = array(
'all' => __( 'All registered sizes (WordPress default)', 'idrivee2-media-upload' ),
'thumbnail' => __( 'Only thumbnail (faster uploads)', 'idrivee2-media-upload' ),
'none' => __( 'No sub-sizes (original only)', 'idrivee2-media-upload' ),
);
foreach ( $mode_options as $value => $label ) {
printf(
'<option value="%s"%s>%s</option>',
esc_attr( $value ),
selected( $subsizes_mode, $value, false ),
esc_html( $label )
);
}
?>
</select>
<?php
// Disabled selects are not submitted with the form; preserve the
// constant-defined value via a hidden input so it is not lost on save.
if ( $subsizes_mode_in_config ) {
printf(
'<input type="hidden" name="idrivee2_media_settings[subsizes_mode]" value="%s" />',
esc_attr( $subsizes_mode )
);
}
?>
<p class="description">
<?php
if ( $subsizes_mode_in_config ) {
esc_html_e( 'Defined in wp-config.php (IDRIVEE2_MEDIA_SUBSIZES_MODE)', 'idrivee2-media-upload' );
} else {
esc_html_e( 'Reduces work for large uploads (e.g. camera files). Also disables the -scaled derivative in thumbnail/none modes.', 'idrivee2-media-upload' );
}
?>
</p>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Data Cleanup', 'idrivee2-media-upload' ); ?></th>
<td>
<label for="idrivee2_delete_on_uninstall">
<input
type="checkbox"
id="idrivee2_delete_on_uninstall"
name="idrivee2_media_settings[delete_on_uninstall]"
value="1"
<?php checked( $delete_on_uninstall ); ?>
/>
<?php esc_html_e( 'Delete all plugin data when the plugin is uninstalled', 'idrivee2-media-upload' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'By default, all data is preserved when the plugin is uninstalled. Check this to remove settings, statistics, and post meta on uninstall.', 'idrivee2-media-upload' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<?php if ( $any_in_config ) : ?>
<p class="description">
<?php esc_html_e( 'To modify settings defined in wp-config.php, please edit your wp-config.php file directly.', 'idrivee2-media-upload' ); ?>
</p>
<?php endif; ?>
<?php submit_button( __( 'Save Settings', 'idrivee2-media-upload' ) ); ?>
</form>
<?php if ( $is_configured ) : ?>
<hr />
<h2><?php esc_html_e( 'Test Connection', 'idrivee2-media-upload' ); ?></h2>
<p><?php esc_html_e( 'Test your S3 configuration to ensure everything is working correctly.', 'idrivee2-media-upload' ); ?></p>
<?php
// Display test results if available.
$test_result_raw = get_transient( 'idrivee2_test_result' );
if ( is_array( $test_result_raw ) ) {
/**
* Typed test result data from transient.
*
* @var array{type: string, message: string, file_name?: string, object_url?: string} $test_result
*/
$test_result = $test_result_raw;
delete_transient( 'idrivee2_test_result' );
$notice_class = 'notice-' . $test_result['type'];
?>
<div class="notice <?php echo esc_attr( $notice_class ); ?>">
<p><strong><?php echo wp_kses_post( $test_result['message'] ); ?></strong></p>
<?php if ( isset( $test_result['file_name'], $test_result['object_url'] ) ) : ?>
<p>
<?php
printf(
/* translators: %s is the file name. */
esc_html__( 'File: %s', 'idrivee2-media-upload' ),
'<code>' . esc_html( $test_result['file_name'] ) . '</code>'
);
?>
</p>
<p>
<?php esc_html_e( 'URL:', 'idrivee2-media-upload' ); ?>
<a href="<?php echo esc_url( $test_result['object_url'] ); ?>" target="_blank" rel="noopener noreferrer">
<?php echo esc_html( $test_result['object_url'] ); ?>
</a>
</p>
<form method="post" action="" style="margin-top: 10px;">
<?php wp_nonce_field( 'idrivee2_delete_test' ); ?>
<input type="hidden" name="test_file" value="<?php echo esc_attr( $test_result['file_name'] ); ?>" />
<button type="submit" name="idrivee2_delete_test" class="button button-small">
<?php esc_html_e( 'Delete this file', 'idrivee2-media-upload' ); ?>
</button>
</form>
<?php endif; ?>
</div>
<?php
}
?>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row"><?php esc_html_e( 'Test Connection', 'idrivee2-media-upload' ); ?></th>
<td>
<form method="post" action="">
<?php wp_nonce_field( 'idrivee2_test_connection' ); ?>
<button type="submit" name="idrivee2_test_connection" class="button button-primary">
<?php esc_html_e( 'Test S3 Connection', 'idrivee2-media-upload' ); ?>
</button>
<p class="description">
<?php esc_html_e( 'Verify that your S3 bucket is accessible with the configured credentials.', 'idrivee2-media-upload' ); ?>
</p>
</form>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e( 'Upload Test File', 'idrivee2-media-upload' ); ?></th>
<td>
<form method="post" action="">
<?php wp_nonce_field( 'idrivee2_upload_test' ); ?>
<button type="submit" name="idrivee2_upload_test" class="button button-secondary">
<?php esc_html_e( 'Upload Test File', 'idrivee2-media-upload' ); ?>
</button>
<p class="description">
<?php esc_html_e( 'Upload a test file to S3 with a timestamped name (test-YYYYMMDDHHMMSS.txt). The file will remain in S3 until manually deleted.', 'idrivee2-media-upload' ); ?>
</p>
</form>
</td>
</tr>
</tbody>
</table>
<?php endif; ?>
</div>
<?php
}
}