File: /home/dfwparty/dfwblogger.com/wp-content/plugins/ultimate-elementor/includes/admin/settings-api.php
<?php
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use UltimateElementor\Classes\UAEL_Helper;
use UltimateElementor\Classes\UAEL_Maxmind_Database;
/**
* Class Settings_Api.
*/
class Settings_Api {
/**
* Instance.
*
* @access private
* @var object Class object.
* @since 1.0.0
*/
private static $instance;
/**
* Get the singleton instance of the class.
*
* @return Settings_Api
*/
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Initialize hooks.
*
* @since 1.0.0
* @return void
*/
private function __construct() {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
}
/**
* Register REST API routes.
*
* @since 1.0.0
* @return void
*/
public function register_routes() {
$routes = array(
'/widgets' => 'get_uael_widgets',
'/postskins' => 'get_uael_post_skins',
'/settings' => array('GET' => 'get_uael_settings', 'POST' => 'save_uael_settings'),
'/branding' => array('GET' => 'get_uael_branding', 'POST' => 'save_uael_branding'),
'/plugins' => 'get_plugins_list',
'/validateApiKey' => 'validate_google_places_api_key',
'/templates' => 'get_templates_status',
'/mcp-settings' => array( 'GET' => 'get_mcp_settings', 'POST' => 'update_mcp_settings' ),
'/mcp-abilities' => 'get_mcp_abilities',
);
foreach ( $routes as $route => $callback ) {
if ( is_array( $callback ) ) {
foreach ( $callback as $method => $cb ) {
register_rest_route(
'uael/v1',
$route,
array(
'methods' => $method,
'callback' => array( $this, $cb ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
)
);
}
} else {
$call_method = ( '/validateApiKey' === $route ) ? 'POST' : 'GET';
register_rest_route(
'uael/v1',
$route,
array(
'methods' => $call_method,
'callback' => array( $this, $callback ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
)
);
}
}
}
/**
* Get Starter Templates Status.
*/
public function get_templates_status( WP_REST_Request $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$templates_status = UAEL_Helper::starter_templates_status();
$response_data = array(
'templates_status' => $templates_status,
);
if ( 'Activated' === $templates_status ) {
$response_data['redirect_url'] = UAEL_Helper::starter_templates_link();
}
return new WP_REST_Response( $response_data, 200 );
}
/**
* Validate Google Places API key.
*/
public function validate_google_places_api_key( WP_REST_Request $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$api_key = $request->get_param( 'apiKey' );
$api_type = $request->get_param( 'source' );
if( 'google' === $api_type || 'yelp' === $api_type ) {
// Perform your API key validation logic here.
UAEL_Helper::get_api_authentication( $api_type, $api_key );
if( 'google' === $api_type ) {
$google_status = get_option( 'uael_google_api_status' );
if ( 'yes-new' === $google_status || 'yes' === $google_status ) {
return new WP_REST_Response( array( 'success' => true, 'message' => __( 'Your API key authenticated successfully!', 'uael' ) ), 200 );
} elseif ( 'no' === $google_status ) {
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Entered API key is invalid', 'uael' ) ), 400 );
} elseif ( 'exceeded' === $google_status ) {
$error_message = sprintf(
'%1$s%s%2$s %3$s%s%4$s',
'<b>' . __( 'Google Error Message:', 'uael' ) . '</b>',
__( 'You have exceeded your daily request quota for this API. If you did not set a custom daily request quota, verify your project has an active billing account.', 'uael' ),
'<a href="http://g.co/dev/maps-no-account" target="_blank" rel="noopener">',
__( 'Click here to enable billing.', 'uael' ),
'</a>'
);
return new WP_REST_Response( array( 'success' => false, 'message' => $error_message ), 400 );
} else {
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Unknown error', 'uael' ) ), 400 );
}
}
if( 'yelp' === $api_type ) {
$yelp_status = get_option( 'uael_yelp_api_status' );
if ( 'yes' === $yelp_status ) {
return new WP_REST_Response( array( 'success' => true, 'message' => __( 'Your API key authenticated successfully!', 'uael' ) ), 200 );
} elseif ( 'no' === $yelp_status ) {
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Entered API key is invalid', 'uael' ) ), 400 );
} else {
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Unknown error', 'uael' ) ), 400 );
}
}
} else if( 'facebook' === $api_type ) {
$response = UAEL_Helper::facebook_token_authentication( $api_key );
if ( 200 === $response ) {
return new WP_REST_Response( array( 'success' => true, 'message' => __( 'Access Token authenticated successfully!', 'uael' ) ), 200 );
} else {
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Invalid Access Token', 'uael' ) ), 400 );
}
}
return new WP_REST_Response( array( 'success' => false, 'message' => __( 'Unknown error', 'uael' ) ), 400 );
}
/**
* Check whether a given request has permission to read notes.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_Error|boolean
*/
public function get_items_permissions_check( $request = null ) {
if ( ! current_user_can( 'manage_options' ) ) {
return new \WP_Error( 'uae_rest_not_allowed', __( 'Sorry, you are not authorized to perform this action.', 'uael' ), array( 'status' => 403 ) );
}
// Verify the REST nonce here (the permission_callback) so unauthorized or
// CSRF requests are rejected with a 403 before any route callback runs,
// instead of relying on a manual check inside each callback body.
$nonce = ( $request instanceof \WP_REST_Request ) ? $request->get_header( 'X-WP-Nonce' ) : '';
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new \WP_Error( 'uae_rest_invalid_nonce', __( 'Invalid nonce.', 'uael' ), array( 'status' => 403 ) );
}
return true;
}
/**
* Callback function to return settings.
*
* @return WP_REST_Response
*/
public function get_uael_widgets( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$all_widgets = UAEL_Helper::get_all_widgets_list();
if ( ! is_array( $all_widgets ) ) {
return new WP_REST_Response( array( 'message' => __( 'Widgets not found', 'uael' ) ), 404 ); // Return not found response
}
return new WP_REST_Response( $all_widgets, 200 );
}
/**
* Callback function to return settings.
*
* @return WP_REST_Response
*/
public function get_uael_post_skins( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$post_skins = UAEL_Helper::get_post_skin_options();
if ( ! is_array( $post_skins ) ) {
return new WP_REST_Response( array( 'message' => __( 'Not found', 'uael' ) ), 404 ); // Return not found response
}
return new WP_REST_Response( $post_skins, 200 );
}
/**
* Callback function to return settings.
*
* @return WP_REST_Response
*/
public function get_uael_settings( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Fetch your settings here
$settings = UAEL_Helper::get_admin_settings_option( '_uael_integration', array(), true );
if ( ! is_array( $settings ) ) {
return new WP_REST_Response( array( 'message' => __( 'Settings not found', 'uael' ) ), 404 ); // Return not found response
}
return new WP_REST_Response( $settings, 200 );
}
public function save_uael_settings( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Get the settings from the request
$settings = $request->get_json_params();
$new_settings = array();
$maxmind_status = 'success';
// Verify MaxMind key and download database
if ( isset( $settings['uael_maxmind_geolocation_license_key'] ) ) {
$geolite_db = new UAEL_Maxmind_Database();
$result = $geolite_db->verify_key_and_download_database( $settings['uael_maxmind_geolocation_license_key'] );
if ( isset( $result['error'] ) && $result['error'] ) {
$maxmind_status = 'error';
}
}
// Allow-list of integration setting keys (mirrors the integrations-update
// ability) so arbitrary keys can't be written into _uael_integration.
$allowed_keys = array(
'google_api',
'developer_mode',
'language',
'google_places_api',
'yelp_api',
'recaptcha_v3_key',
'recaptcha_v3_secretkey',
'recaptcha_v3_score',
'google_client_id',
'facebook_app_id',
'facebook_app_secret',
'uael_share_button',
'uael_maxmind_geolocation_license_key',
'uael_maxmind_geolocation_db_path',
'uael_twitter_feed_consumer_key',
'uael_twitter_feed_consumer_secret',
'instagram_app_id',
'instagram_app_secret',
'instagram_app_token',
);
// Loop through the input and sanitize each allow-listed value.
foreach ( (array) $settings as $key => $val ) {
if ( ! in_array( $key, $allowed_keys, true ) ) {
continue;
}
if ( is_array( $val ) ) {
foreach ( $val as $k => $v ) {
$new_settings[ $key ][ $k ] = sanitize_text_field( $v );
}
} else {
$new_settings[ $key ] = sanitize_text_field( $val );
}
}
// Save the settings back to the database
UAEL_Helper::update_admin_settings_option( '_uael_integration', $new_settings, true );
return new WP_REST_Response( array(
'message' => __( 'Settings saved successfully', 'uael' ),
'maxmind_status' => $maxmind_status
), 200 );
}
/**
* Callback function to return plugins list.
*
* @return WP_REST_Response
*/
public function get_plugins_list( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Fetch branding settings
$plugins_list = UAEL_Helper::get_bsf_plugins_list();
if ( ! is_array( $plugins_list ) ) {
return new WP_REST_Response( array( 'message' => __( 'Plugins list not found', 'uael' ) ), 404 );
}
return new WP_REST_Response( $plugins_list, 200 );
}
/**
* Callback function to return settings.
*
* @return WP_REST_Response
*/
public function get_uael_branding( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Fetch branding settings
$branding_settings = UAEL_Helper::get_white_labels();
if ( ! is_array( $branding_settings ) ) {
return new WP_REST_Response( array( 'message' => __( 'Branding settings not found', 'uael' ) ), 404 );
}
return new WP_REST_Response( $branding_settings, 200 );
}
public function save_uael_branding( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Get the settings from the request
$settings = $request->get_json_params();
$stored_settings = UAEL_Helper::get_white_labels();
// Sanitize and prepare the settings for saving
$new_settings = array();
// Allow-list + URL escaping (mirrors the branding-update ability) so
// arbitrary keys can't be stored and URL fields can't carry javascript:
// schemes that would render as href in admin pages.
$allowed_keys = array(
'agency',
'plugin',
'replace_logo',
'enable_knowledgebase',
'knowledgebase_url',
'enable_support',
'support_url',
'enable_beta_box',
'enable_custom_tagline',
'internal_help_links',
'logo_url',
);
$url_keys = array( 'knowledgebase_url', 'support_url', 'logo_url' );
$nested_url_keys = array( 'agency' => array( 'author_url' ) );
if ( is_array( $settings ) ) {
foreach ( $settings as $key => $val ) {
if ( ! in_array( $key, $allowed_keys, true ) ) {
continue;
}
if ( is_array( $val ) ) {
$nested_urls = isset( $nested_url_keys[ $key ] ) ? $nested_url_keys[ $key ] : array();
foreach ( $val as $k => $v ) {
$new_settings[ $key ][ $k ] = in_array( $k, $nested_urls, true ) ? esc_url_raw( $v ) : sanitize_text_field( $v );
}
} elseif ( in_array( $key, $url_keys, true ) ) {
$new_settings[ $key ] = esc_url_raw( $val );
} else {
$new_settings[ $key ] = sanitize_text_field( $val );
}
}
}
if ( ! isset( $new_settings['agency']['hide_branding'] ) ) {
$new_settings['agency']['hide_branding'] = false;
} else {
// Add a hide branding component option
}
$checkbox_var = array(
'replace_logo',
'internal_help_links',
);
foreach ( $checkbox_var as $key => $value ) {
if ( ! isset( $new_settings[ $value ] ) ) {
$new_settings[ $value ] = 'disable';
}
}
$new_settings = wp_parse_args( $new_settings, $stored_settings );
// Save the settings back to the database
UAEL_Helper::update_admin_settings_option( '_uael_white_label', $new_settings, true );
return new WP_REST_Response( 'Branding settings saved successfully', 200 );
}
/**
* Get MCP abilities list for AI Tools settings page.
*
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response
*/
public function get_mcp_abilities( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
// Ensure handlers are populated — wp_abilities_api_init may not have fired yet.
$this->ensure_active_handlers_loaded();
$registry = $this->get_active_registry();
if ( ! $registry ) {
return new WP_REST_Response( array(), 200 );
}
$abilities = $registry->get_abilities_info();
$settings = get_option( 'uae_mcp_settings', array() );
$disabled = ! empty( $settings['disabled_abilities'] ) && is_array( $settings['disabled_abilities'] )
? $settings['disabled_abilities']
: array();
foreach ( $abilities as &$ability ) {
$ability['is_enabled'] = ! in_array( $ability['name'], $disabled, true )
&& ! in_array( $ability['full_name'], $disabled, true );
}
unset( $ability );
return new WP_REST_Response( $abilities, 200 );
}
/**
* Get MCP settings.
*
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response
*/
public function get_mcp_settings( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$defaults = array(
'enable_abilities' => false,
'allow_modifications' => true,
'dedicated_server' => false,
'angie_enabled' => false,
'disabled_abilities' => array(),
);
$settings = get_option( 'uae_mcp_settings', array() );
$settings = wp_parse_args( $settings, $defaults );
$settings['is_abilities_api_active'] = function_exists( 'wp_register_ability' );
$settings['is_mcp_adapter_active'] = class_exists( '\WP\MCP\Core\McpAdapter' );
$settings['is_angie_active'] = class_exists( 'Elementor\Plugin' );
$settings['dedicated_server_url'] = rest_url( 'uae/mcp' );
$settings['total_abilities'] = $this->count_uael_abilities();
return new WP_REST_Response( $settings, 200 );
}
/**
* Update MCP settings.
*
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response|WP_Error
*/
public function update_mcp_settings( $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'invalid_nonce', __( 'Invalid nonce', 'uael' ), array( 'status' => 403 ) );
}
$defaults = array(
'enable_abilities' => false,
'allow_modifications' => true,
'dedicated_server' => false,
'angie_enabled' => false,
'disabled_abilities' => array(),
);
$current = get_option( 'uae_mcp_settings', array() );
$current = wp_parse_args( $current, $defaults );
$allowed_keys = array_keys( $defaults );
$params = $request->get_json_params();
if ( ! is_array( $params ) ) {
return new WP_Error( 'invalid_params', __( 'Invalid parameters.', 'uael' ), array( 'status' => 400 ) );
}
foreach ( $allowed_keys as $key ) {
if ( ! isset( $params[ $key ] ) ) {
continue;
}
if ( 'disabled_abilities' === $key ) {
$current[ $key ] = is_array( $params[ $key ] )
? array_values( array_map( 'sanitize_text_field', $params[ $key ] ) )
: array();
} else {
$current[ $key ] = (bool) $params[ $key ];
}
}
// Autoload disabled — this option is only needed when the AI Tools
// settings/abilities are actually loaded, not on every front-end request.
update_option( 'uae_mcp_settings', $current, false );
return new WP_REST_Response(
array(
'success' => true,
'settings' => $current,
),
200
);
}
/**
* Get the active ability registry.
*
* In standalone mode: Pro's own registry.
* In dual mode: HFE's registry (which includes Pro's handlers).
*
* @return object|null Registry instance or null.
*/
private function get_active_registry() {
// Try Pro's own registry first (standalone mode).
$bootstrap = class_exists( 'UAEL_Abilities_Bootstrap' ) ? UAEL_Abilities_Bootstrap::instance() : null;
$registry = $bootstrap ? $bootstrap->get_registry() : null;
if ( $registry ) {
return $registry;
}
// Dual mode: use HFE's registry.
if ( class_exists( 'HFE_Abilities_Loader' ) ) {
$hfe_loader = HFE_Abilities_Loader::instance();
if ( method_exists( $hfe_loader, 'get_registry' ) ) {
return $hfe_loader->get_registry();
}
}
return null;
}
/**
* Ensure the active registry has handlers loaded.
*
* Calls ensure_handlers_loaded() on whichever bootstrap is active
* (Pro standalone or HFE dual mode).
*
* @return void
*/
private function ensure_active_handlers_loaded() {
// Use Pro's own bootstrap ONLY in standalone mode — i.e. when it actually
// owns a registry. In dual mode Pro has no registry of its own (its
// handlers are registered into HFE's registry), so we must ensure HFE's
// loader instead. Otherwise the registry that get_active_registry()
// returns (HFE's) is never populated on Pro's settings page and the
// abilities list/count come back empty. Mirrors get_active_registry().
$bootstrap = class_exists( 'UAEL_Abilities_Bootstrap' ) ? UAEL_Abilities_Bootstrap::instance() : null;
if ( $bootstrap
&& method_exists( $bootstrap, 'get_registry' ) && $bootstrap->get_registry()
&& method_exists( $bootstrap, 'ensure_handlers_loaded' ) ) {
$bootstrap->ensure_handlers_loaded();
return;
}
// Dual mode (or Pro has no registry of its own): use HFE's loader, which
// also fires uae_mcp_register_abilities so Pro's handlers join HFE's registry.
if ( class_exists( 'HFE_Abilities_Loader' ) ) {
$hfe_loader = HFE_Abilities_Loader::instance();
if ( method_exists( $hfe_loader, 'ensure_handlers_loaded' ) ) {
$hfe_loader->ensure_handlers_loaded();
}
}
}
/**
* Count registered abilities.
*
* @return int
*/
private function count_uael_abilities() {
if ( ! function_exists( 'wp_get_abilities' ) ) {
return 0;
}
// Count via wp_get_abilities() rather than the registry's discover()-
// populated names. discover() only runs on wp_abilities_api_init, which
// on the settings page may not have fired yet (e.g. when the MCP Adapter
// is inactive) — leaving get_registered_names() empty and the count at 0.
// wp_get_abilities() lazily fires that hook and performs registration,
// so the total is correct with or without the MCP Adapter. Mirrors the
// Lite plugin's count.
$all_abilities = wp_get_abilities();
$count = 0;
$prefix = class_exists( 'UAEL_Ability_Registry' ) ? UAEL_Ability_Registry::PREFIX : 'uae/';
foreach ( $all_abilities as $ability_name => $ability ) {
if ( 0 === strpos( $ability_name, $prefix ) ) {
++$count;
}
}
return $count;
}
}
// Initialize the Settings_Api class
Settings_Api::get_instance();