| Server IP : 121.121.20.254 / Your IP : 216.73.216.146 Web Server : Microsoft-IIS/10.0 System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64 User : IUSR ( 0) PHP Version : 8.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/inetpub/wwwroot/AIWEBSTATION/wp-content/plugins/aitoel-html-importer/includes/ |
Upload File : |
<?php
defined('ABSPATH') || exit;
/**
* Admin pages — conversion UI and settings.
*/
class HTEL_Admin {
/**
* Register admin menu pages.
*/
public static function register_menu() {
// Top-level menu
add_menu_page(
__('AI to Elementor', 'aitoel-html-importer'),
__('AI to Elementor', 'aitoel-html-importer'),
'edit_posts',
'htel-convert',
array(__CLASS__, 'render_convert_page'),
'data:image/svg+xml;base64,' . base64_encode('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path d="M10 2L3 7v6l7 5 7-5V7l-7-5zm0 2.18L14.5 7.5 10 10.82 5.5 7.5 10 4.18zM5 8.82l4 2.86v3.5L5 12.32v-3.5zm10 0v3.5l-4 2.86v-3.5l4-2.86z"/></svg>'),
58 // Position: after Appearance (60) but before typical plugins
);
// Convert submenu (replaces the auto-generated duplicate)
add_submenu_page(
'htel-convert',
__('Convert', 'aitoel-html-importer'),
__('Convert', 'aitoel-html-importer'),
'edit_posts',
'htel-convert',
array(__CLASS__, 'render_convert_page')
);
// Settings submenu
add_submenu_page(
'htel-convert',
__('Settings', 'aitoel-html-importer'),
__('Settings', 'aitoel-html-importer'),
'manage_options',
'htel-settings',
array(__CLASS__, 'render_settings_page')
);
}
/**
* Register settings.
*/
public static function register_settings() {
register_setting('htel_settings', 'htel_api_url', array(
'type' => 'string',
'sanitize_callback' => array(__CLASS__, 'sanitize_api_url'),
'default' => HTEL_API_URL,
));
register_setting('htel_settings', 'htel_telemetry_opt_in', array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
'default' => false,
));
// Conversion Quality Sampling — opt-OUT (see ToS §9.4).
// Default false means sampling is ON; user checks to disable.
register_setting('htel_settings', 'htel_sampling_opt_out', array(
'type' => 'boolean',
'sanitize_callback' => 'rest_sanitize_boolean',
'default' => false,
));
// Global Colors mapping is deliberately NOT registered here. The feature is built
// end-to-end (API `globalize` + inject_global_colors() below in class-converter) but
// held back from release — George's call, 2026-08-07 ("option B"). Reinstating it is
// the register_setting + the Settings checkbox + the option-read in convert(); the
// response-side injection path below is kept and inert without them.
}
/**
* Sanitize callback for the htel_api_url setting.
*
* Refuses to persist an empty or malformed value — falls back to the
* existing stored value (if it was valid) or to HTEL_API_URL constant.
*
* Why this is necessary on top of get_api_url() self-healing:
* - get_api_url() is the READ path. Self-healing there means an
* accidentally-saved-empty option silently disappears on next read.
* That's defense-in-depth, but the customer's UI experience is
* "I saved something, then it vanished" — confusing.
* - This sanitize callback is the WRITE path. We refuse the bad
* value at submit time and surface an admin notice explaining why.
* The customer sees: "the API URL field can't be empty; reverted
* to https://api.aitoelementor.com" — much clearer.
*
* Tests in wp-plugin/tests/test-settings-sanitize.php enforce this.
*/
public static function sanitize_api_url($value) {
// Trim whitespace; many "empty" submissions are actually whitespace
$value = is_string($value) ? trim($value) : '';
// Valid URL with http(s) scheme — accept (esc_url_raw for safety)
if ($value !== ''
&& preg_match('#^https?://[^\s/]+#i', $value)
&& filter_var($value, FILTER_VALIDATE_URL)) {
$clean = esc_url_raw($value);
return rtrim($clean, '/');
}
// Surface an admin notice so the user knows their submission was
// refused (rather than silently saved-and-then-defaulted).
add_settings_error(
'htel_api_url',
'htel_api_url_invalid',
sprintf(
/* translators: %s is the canonical API URL */
esc_html__('The API URL must be a complete URL with http:// or https://. Reverted to %s.', 'aitoel-html-importer'),
esc_html(HTEL_API_URL)
),
'error'
);
// Fall back to existing valid stored value, otherwise the constant
$existing = get_option('htel_api_url', '');
if (is_string($existing) && $existing !== ''
&& preg_match('#^https?://[^\s/]+#i', $existing)
&& filter_var($existing, FILTER_VALIDATE_URL)) {
return rtrim($existing, '/');
}
return HTEL_API_URL;
}
/**
* Enqueue admin CSS and JS on our pages only.
*/
public static function enqueue_assets($hook) {
// Match our pages regardless of how WP sanitizes the menu title
if (strpos($hook, 'htel-convert') === false && strpos($hook, 'htel-settings') === false) {
return;
}
wp_enqueue_style(
'htel-admin',
HTEL_PLUGIN_URL . 'assets/css/admin.css',
array(),
HTEL_VERSION
);
wp_enqueue_script(
'htel-admin',
HTEL_PLUGIN_URL . 'assets/js/admin.js',
array('jquery'),
HTEL_VERSION,
true
);
$license_status = HTEL_License::get_status();
$has_license = ($license_status === 'active' && !empty(HTEL_License::get_key()));
wp_localize_script('htel-admin', 'htel_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'convert_nonce' => wp_create_nonce('htel_convert_nonce'),
'license_nonce' => wp_create_nonce('htel_license_nonce'),
'has_license' => $has_license ? '1' : '0',
));
}
/**
* Render the conversion page.
*/
public static function render_convert_page() {
include HTEL_PLUGIN_DIR . 'templates/admin-page.php';
}
/**
* Render the settings page.
*/
public static function render_settings_page() {
include HTEL_PLUGIN_DIR . 'templates/settings-page.php';
}
}