'ajax_create_link', 'useclick_get_links' => 'ajax_get_links', 'useclick_update_link' => 'ajax_update_link', 'useclick_delete_link' => 'ajax_delete_link', 'useclick_get_domains' => 'ajax_get_domains', 'useclick_get_account' => 'ajax_get_account', 'useclick_verify_api_key' => 'ajax_verify_api_key', ); foreach ( $ajax as $action => $method ) { add_action( 'wp_ajax_' . $action, array( __CLASS__, $method ) ); } } /** * Capability required for the plugin's screens and link management. * * @return string */ public static function capability() { /** * Filters the capability needed to use the UseClick.io admin screens. * * @param string $capability Default 'manage_options'. */ return (string) apply_filters( 'useclick_capability', 'manage_options' ); } /** * Whether an API key is saved. * * @return bool */ public static function has_api_key() { return '' !== useclick_get_api_key(); } /** * Admin menu. */ public static function add_menu() { $cap = self::capability(); self::$page_hooks[] = add_menu_page( __( 'UseClick.io', 'useclick' ), __( 'UseClick.io', 'useclick' ), $cap, 'useclick', array( __CLASS__, 'render_dashboard_page' ), self::menu_icon(), 30 ); self::$page_hooks[] = add_submenu_page( 'useclick', __( 'Create short link', 'useclick' ), __( 'Create link', 'useclick' ), $cap, 'useclick', array( __CLASS__, 'render_dashboard_page' ) ); self::$page_hooks[] = add_submenu_page( 'useclick', __( 'Short links', 'useclick' ), __( 'Short links', 'useclick' ), $cap, 'useclick-links', array( __CLASS__, 'render_links_page' ) ); self::$page_hooks[] = add_submenu_page( 'useclick', __( 'Website analytics', 'useclick' ), __( 'Website analytics', 'useclick' ), $cap, 'useclick-analytics', array( 'UseClick_Analytics', 'render_admin_page' ) ); self::$page_hooks[] = add_submenu_page( 'useclick', __( 'UseClick.io settings', 'useclick' ), __( 'Settings', 'useclick' ), $cap, 'useclick-settings', array( 'UseClick_Settings', 'render_page' ) ); foreach ( self::$page_hooks as $hook ) { add_action( 'load-' . $hook, array( __CLASS__, 'add_help_tabs' ) ); } } /** * The "Help" tab (top right of every UseClick.io screen): how to get an API key, with links to the guide. */ public static function add_help_tabs() { $screen = get_current_screen(); if ( ! $screen ) { return; } $new_tab = ' ' . esc_html__( '(opens in a new tab)', 'useclick' ) . ''; $screen->add_help_tab( array( 'id' => 'useclick-api-key', 'title' => __( 'Connect your account', 'useclick' ), 'content' => '

' . esc_html__( 'Easiest: on UseClick.io > Settings, click Connect with useClick.io, sign in (or create a free account) and confirm. The plugin gets its own API key; nothing to copy.', 'useclick' ) . '

' . '

' . esc_html__( 'To create and paste a key yourself instead:', 'useclick' ) . '

' . '
    ' . '
  1. ' . sprintf( /* translators: 1: sign-in link, 2: sign-up link */ esc_html__( '%1$s at useclick.io, or %2$s.', 'useclick' ), '' . esc_html__( 'Sign in', 'useclick' ) . $new_tab . '', '' . esc_html__( 'create a free account', 'useclick' ) . $new_tab . '' ) . '
  2. ' . '
  3. ' . esc_html__( 'Open Account > API keys in the dashboard and click "+ Create API key".', 'useclick' ) . '
  4. ' . '
  5. ' . esc_html__( 'Name the key after this site (for example "WordPress: example.com") and click "Create key".', 'useclick' ) . '
  6. ' . '
  7. ' . esc_html__( 'Copy the key (it starts with uc_live_). It is shown only once.', 'useclick' ) . '
  8. ' . '
  9. ' . esc_html__( 'In WordPress, open UseClick.io > Settings > Or paste an API key, paste it and click Connect.', 'useclick' ) . '
  10. ' . '
', ) ); $screen->add_help_tab( array( 'id' => 'useclick-troubleshooting', 'title' => __( 'Troubleshooting', 'useclick' ), 'content' => '

' . esc_html__( 'The key is not accepted', 'useclick' ) . '
' . esc_html__( 'Copy it again without spaces, and check under Account > API keys in UseClick.io that it is still Active. A lost key cannot be shown again: create a new one and revoke the old one.', 'useclick' ) . '

' . '

' . esc_html__( 'Could not reach UseClick.io', 'useclick' ) . '
' . esc_html__( 'A firewall or security plugin is blocking outgoing requests. Allow HTTPS requests to useclick.io, or ask your host.', 'useclick' ) . '

' . '

' . esc_html__( 'Rate limit reached', 'useclick' ) . '
' . esc_html__( 'Wait a minute. After upgrading your plan, create a new key to get the higher limit.', 'useclick' ) . '

', ) ); $screen->set_help_sidebar( '

' . esc_html__( 'More help', 'useclick' ) . '

' . '

' . esc_html__( 'WordPress plugin guide', 'useclick' ) . $new_tab . '

' . '

' . esc_html__( 'API keys guide', 'useclick' ) . $new_tab . '

' . '

' . esc_html__( 'Plans and limits', 'useclick' ) . $new_tab . '

' ); } /** * Monochrome SVG menu icon (WordPress recolours it to match the admin scheme). * * @return string */ private static function menu_icon() { $svg = '' . self::logo_paths( 'black' ) . ''; // base64 is required by the WordPress menu icon API for data URIs. return 'data:image/svg+xml;base64,' . base64_encode( $svg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode } /** * Paths of the UseClick.io mark (viewBox 0 0 151 150), all filled so WordPress can recolour the menu icon. * * @param string $color Fill colour. * @return string */ public static function logo_paths( $color ) { $fill = esc_attr( $color ); return '' . '' . '' . ''; } /** * "Settings" link on the Plugins screen. * * @param array $links Existing links. * @return array */ public static function action_links( $links ) { $url = admin_url( 'admin.php?page=useclick-settings' ); array_unshift( $links, '' . esc_html__( 'Settings', 'useclick' ) . '' ); return $links; } /** * Load CSS/JS on the plugin's own screens. * * @param string $hook Current admin page hook suffix. */ public static function enqueue_assets( $hook ) { if ( ! in_array( $hook, self::$page_hooks, true ) ) { return; } self::register_assets(); wp_enqueue_style( 'useclick-admin' ); wp_enqueue_script( 'useclick-admin' ); } /** * Register the shared stylesheet and script (also used on post screens). */ public static function register_assets() { if ( wp_script_is( 'useclick-admin', 'registered' ) ) { return; } wp_register_style( 'useclick-admin', USECLICK_PLUGIN_URL . 'assets/css/admin.css', array(), USECLICK_VERSION ); wp_register_script( 'useclick-admin', USECLICK_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery', 'wp-a11y' ), USECLICK_VERSION, true ); $config = array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'useclick_nonce' ), 'appUrl' => USECLICK_APP_URL, 'pricingUrl' => USECLICK_APP_URL . '/pricing', 'dashboardUrl' => USECLICK_APP_URL . '/dashboard', /** This filter is documented in includes/class-useclick-admin.php (short_domain()). */ 'shortDomain' => self::short_domain(), 'planLabels' => array( 'free' => self::plan_label( 'free' ), 'starter' => self::plan_label( 'starter' ), 'growth' => self::plan_label( 'growth' ), 'pro' => self::plan_label( 'pro' ), 'business' => self::plan_label( 'business' ), ), 'i18n' => self::js_strings(), ); wp_add_inline_script( 'useclick-admin', 'window.useclickData = ' . wp_json_encode( $config ) . ';', 'before' ); } /** * The built-in short domain, shown when the domain list cannot be loaded. * * @return string */ public static function short_domain() { /** * Filters the built-in short domain shown as a fallback in the domain picker. * * @param string $domain Default uclk.me. */ return (string) apply_filters( 'useclick_short_domain', 'uclk.me' ); } /** * Translated strings for admin.js. * * @return array */ private static function js_strings() { return array( 'creating' => __( 'Creating...', 'useclick' ), 'createLink' => __( 'Create short link', 'useclick' ), 'linkCreated' => __( 'Short link created', 'useclick' ), 'copy' => __( 'Copy', 'useclick' ), 'copied' => __( 'Copied', 'useclick' ), 'viewAnalytics' => __( 'View analytics', 'useclick' ), 'analytics' => __( 'Analytics', 'useclick' ), 'invalidUrl' => __( 'Enter a full destination URL that starts with http:// or https://.', 'useclick' ), 'unknownError' => __( 'Something went wrong. Please try again.', 'useclick' ), 'networkError' => __( 'The request to WordPress failed. Check your connection and try again.', 'useclick' ), 'loadingLinks' => __( 'Loading links...', 'useclick' ), 'noLinks' => __( 'No links yet. Create your first short link on the Create link screen.', 'useclick' ), 'noMatches' => __( 'No links match your search.', 'useclick' ), 'colShortLink' => __( 'Short link', 'useclick' ), 'colTargetUrl' => __( 'Destination', 'useclick' ), 'colCampaign' => __( 'Campaign', 'useclick' ), 'colClicks' => __( 'Clicks', 'useclick' ), 'colCreated' => __( 'Created', 'useclick' ), 'colActions' => __( 'Actions', 'useclick' ), 'geoTargeted' => __( 'Geo-targeted', 'useclick' ), 'editLink' => __( 'Edit', 'useclick' ), 'deleteLink' => __( 'Delete', 'useclick' ), /* translators: %s: short link slug */ 'deleteConfirm' => __( 'Delete the short link "%s"? Visitors who open it will get an error page. This cannot be undone.', 'useclick' ), 'linkUpdated' => __( 'Link updated.', 'useclick' ), 'nothingChanged' => __( 'Nothing to update.', 'useclick' ), 'updating' => __( 'Saving...', 'useclick' ), 'updateLink' => __( 'Save changes', 'useclick' ), 'linkDeleted' => __( 'Link deleted.', 'useclick' ), 'copiedToClipboard' => __( 'Short link copied to the clipboard.', 'useclick' ), 'duplicateCountries' => __( 'Each country can only be used once. Remove the duplicate country.', 'useclick' ), 'verifying' => __( 'Checking...', 'useclick' ), 'verifyKey' => __( 'Test key', 'useclick' ), 'enterKey' => __( 'Paste an API key first.', 'useclick' ), /* translators: %s: plan name, e.g. Starter */ 'keyValid' => __( 'Key accepted. Plan: %s.', 'useclick' ), /* translators: 1: current page, 2: total pages */ 'pageOf' => __( 'Page %1$s of %2$s', 'useclick' ), /* translators: %s: number of links */ 'items' => __( '%s links', 'useclick' ), /* translators: 1: links used, 2: plan limit */ 'linksUsage' => __( '%1$s of %2$s', 'useclick' ), /* translators: %s: plan name, e.g. Starter */ 'upgradeForFeature' => __( 'Available on the %s plan and above.', 'useclick' ), 'upgradeCta' => __( 'See plans', 'useclick' ), 'freeCantEditDest' => __( 'Changing the destination needs the Starter plan or above.', 'useclick' ), 'previous' => __( 'Previous page', 'useclick' ), 'next' => __( 'Next page', 'useclick' ), /* translators: %s: plan name, e.g. Starter. Badge on features that need that plan or above. */ 'planPlus' => __( '%s+', 'useclick' ), ); } /** * Remember a status message for the current user's next view of one of our screens (after a * form handler redirects), instead of passing it in the URL. * * @param string $page Screen slug, e.g. useclick-analytics. * @param string $status Status key. */ public static function set_flash( $page, $status ) { set_transient( 'useclick_flash_' . get_current_user_id(), $page . '|' . $status, 5 * MINUTE_IN_SECONDS ); } /** * The status message waiting for this screen (once), or ''. * * @param string $page Screen slug. * @return string */ public static function take_flash( $page ) { $key = 'useclick_flash_' . get_current_user_id(); $value = (string) get_transient( $key ); if ( 0 !== strpos( $value, $page . '|' ) ) { return ''; } delete_transient( $key ); return sanitize_key( substr( $value, strlen( $page ) + 1 ) ); } /** * Common guard for every AJAX endpoint: nonce and capability. * * @param string $capability Capability to require. Defaults to the plugin capability. */ public static function verify_ajax( $capability = '' ) { check_ajax_referer( 'useclick_nonce', 'nonce' ); if ( ! current_user_can( '' !== $capability ? $capability : self::capability() ) ) { wp_send_json_error( array( 'message' => __( 'You are not allowed to do this.', 'useclick' ) ), 403 ); } } /** * Send a WP_Error to the browser with the details admin.js needs (upgrade link, required plan). * * @param WP_Error $error Error. */ public static function send_error( WP_Error $error ) { $data = $error->get_error_data(); $payload = array( 'message' => $error->get_error_message(), 'code' => $error->get_error_code(), ); if ( is_array( $data ) ) { foreach ( array( 'required_plan', 'upgrade_url', 'feature', 'retry_after', 'status' ) as $key ) { if ( isset( $data[ $key ] ) ) { $payload[ $key ] = $data[ $key ]; } } } wp_send_json_error( $payload ); } /** * Read a string from the POST body (unslashed, not yet sanitized). * * @param string $key Field name. * @return string|null Null when absent. */ private static function post_value( $key ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- nonce checked in verify_ajax(); sanitized by the caller. return isset( $_POST[ $key ] ) ? (string) wp_unslash( $_POST[ $key ] ) : null; } /** * Sanitize link fields sent by the admin screens. * * Only fields present in $raw are returned, so an update sends only what changed. * Empty optional values are dropped on create. * * @param array $raw Unslashed input. * @param bool $is_create Creating (true) or updating (false). * @return array|WP_Error */ public static function sanitize_link_fields( array $raw, $is_create ) { $fields = array(); if ( isset( $raw['target_url'] ) ) { $url = esc_url_raw( trim( $raw['target_url'] ), array( 'http', 'https' ) ); if ( '' === $url ) { return new WP_Error( 'invalid_url', __( 'Enter a full destination URL that starts with http:// or https://.', 'useclick' ) ); } $fields['target_url'] = $url; } elseif ( $is_create ) { return new WP_Error( 'invalid_url', __( 'Enter a destination URL.', 'useclick' ) ); } if ( isset( $raw['slug'] ) && '' !== trim( $raw['slug'] ) ) { $slug = trim( $raw['slug'] ); if ( ! preg_match( '/^[A-Za-z0-9_-]{1,64}$/', $slug ) ) { return new WP_Error( 'invalid_slug', __( 'The custom slug can only contain letters, numbers, hyphens and underscores (up to 64 characters).', 'useclick' ) ); } $fields['slug'] = $slug; } if ( isset( $raw['branded_domain_id'] ) ) { $domain_id = sanitize_text_field( $raw['branded_domain_id'] ); if ( '' !== $domain_id && 'default' !== $domain_id && preg_match( '/^[A-Za-z0-9-]{1,64}$/', $domain_id ) ) { $fields['branded_domain_id'] = $domain_id; } } $text_fields = array( 'campaign', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content' ); foreach ( $text_fields as $key ) { if ( ! isset( $raw[ $key ] ) ) { continue; } $value = sanitize_text_field( $raw[ $key ] ); if ( $is_create && '' === $value ) { continue; } $fields[ $key ] = $value; } if ( isset( $raw['geo_targets'] ) && '' !== $raw['geo_targets'] ) { $decoded = json_decode( $raw['geo_targets'], true ); if ( ! is_array( $decoded ) ) { return new WP_Error( 'invalid_geo', __( 'The country targets could not be read. Remove them and add them again.', 'useclick' ) ); } $countries = self::get_countries(); $targets = array(); foreach ( $decoded as $target ) { $country = isset( $target['country'] ) ? strtoupper( sanitize_text_field( (string) $target['country'] ) ) : ''; $url = isset( $target['target_url'] ) ? esc_url_raw( trim( (string) $target['target_url'] ), array( 'http', 'https' ) ) : ''; if ( ! isset( $countries[ $country ] ) || '' === $url ) { continue; } if ( isset( $targets[ $country ] ) ) { return new WP_Error( 'duplicate_country', __( 'Each country can only be used once. Remove the duplicate country.', 'useclick' ) ); } $targets[ $country ] = array( 'country' => $country, 'target_url' => $url, ); } if ( $targets ) { $fields['geo_targets'] = array_values( $targets ); } } return $fields; } /** * AJAX: create a link from the Create link screen. */ public static function ajax_create_link() { self::verify_ajax(); $raw = array(); foreach ( array( 'target_url', 'slug', 'branded_domain_id', 'campaign', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'geo_targets' ) as $key ) { $value = self::post_value( $key ); if ( null !== $value ) { $raw[ $key ] = $value; } } $fields = self::sanitize_link_fields( $raw, true ); if ( is_wp_error( $fields ) ) { self::send_error( $fields ); } $api = new UseClick_API(); $result = $api->create_link( $fields ); if ( is_wp_error( $result ) ) { self::send_error( $result ); } UseClick_API::flush_cache(); wp_send_json_success( $result ); } /** * AJAX: list links. */ public static function ajax_get_links() { self::verify_ajax(); $page = max( 1, (int) self::post_value( 'paged' ) ); $per_page = self::post_value( 'per_page' ); $per_page = null === $per_page ? 25 : (int) $per_page; $campaign = sanitize_text_field( (string) self::post_value( 'campaign' ) ); $api = new UseClick_API(); $result = $api->get_links( $page, $per_page, $campaign ); if ( is_wp_error( $result ) ) { self::send_error( $result ); } wp_send_json_success( $result ); } /** * AJAX: update a link (only the changed fields are sent). */ public static function ajax_update_link() { self::verify_ajax(); $slug = (string) self::post_value( 'slug' ); if ( ! preg_match( '/^[A-Za-z0-9_-]{1,64}$/', $slug ) ) { self::send_error( new WP_Error( 'invalid_slug', __( 'Unknown link.', 'useclick' ) ) ); } $raw = array(); foreach ( array( 'target_url', 'campaign', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content' ) as $key ) { $value = self::post_value( $key ); if ( null !== $value ) { $raw[ $key ] = $value; } } $fields = self::sanitize_link_fields( $raw, false ); if ( is_wp_error( $fields ) ) { self::send_error( $fields ); } if ( empty( $fields ) ) { wp_send_json_success( array( 'unchanged' => true ) ); } $api = new UseClick_API(); $result = $api->update_link( $slug, $fields ); if ( is_wp_error( $result ) ) { self::send_error( $result ); } UseClick_API::flush_cache(); wp_send_json_success( $result ); } /** * AJAX: delete a link. */ public static function ajax_delete_link() { self::verify_ajax(); $slug = (string) self::post_value( 'slug' ); if ( ! preg_match( '/^[A-Za-z0-9_-]{1,64}$/', $slug ) ) { self::send_error( new WP_Error( 'invalid_slug', __( 'Unknown link.', 'useclick' ) ) ); } $api = new UseClick_API(); $result = $api->delete_link( $slug ); if ( is_wp_error( $result ) ) { self::send_error( $result ); } UseClick_Posts::forget_slug( $slug ); UseClick_API::flush_cache(); wp_send_json_success(); } /** * AJAX: short domains for the domain picker. */ public static function ajax_get_domains() { self::verify_ajax(); $api = new UseClick_API(); $result = $api->get_domains(); if ( is_wp_error( $result ) ) { self::send_error( $result ); } wp_send_json_success( array( 'domains' => $result ) ); } /** * AJAX: account (plan, limits, feature flags) for the saved key. */ public static function ajax_get_account() { self::verify_ajax(); $api = new UseClick_API(); $result = $api->get_account(); if ( is_wp_error( $result ) ) { self::send_error( $result ); } wp_send_json_success( $result ); } /** * AJAX: test a key typed on the Settings screen before saving it. */ public static function ajax_verify_api_key() { self::verify_ajax(); $key = trim( sanitize_text_field( (string) self::post_value( 'api_key' ) ) ); if ( '' === $key ) { self::send_error( new WP_Error( 'no_api_key', __( 'Paste an API key first.', 'useclick' ) ) ); } $api = new UseClick_API( $key ); $result = $api->verify_key(); if ( is_wp_error( $result ) ) { self::send_error( $result ); } $result['plan_label'] = self::plan_label( isset( $result['plan']['plan_name'] ) ? $result['plan']['plan_name'] : 'free' ); wp_send_json_success( $result ); } /** * Human label for a plan id. * * @param string $plan Plan id (free, starter, growth, pro, business). * @return string */ public static function plan_label( $plan ) { $labels = array( 'free' => __( 'Free', 'useclick' ), 'starter' => __( 'Starter', 'useclick' ), 'growth' => __( 'Growth', 'useclick' ), 'pro' => __( 'Pro', 'useclick' ), 'business' => __( 'Business', 'useclick' ), ); $plan = sanitize_key( (string) $plan ); return isset( $labels[ $plan ] ) ? $labels[ $plan ] : ucfirst( $plan ); } /** * Print the branded page header. * * @param string $title Page title. */ public static function render_header( $title ) { $useclick_title = $title; $useclick_account = null; if ( self::has_api_key() ) { $api = new UseClick_API(); $useclick_account = $api->get_account(); } include USECLICK_PLUGIN_DIR . 'templates/partials/header.php'; } /** * Create link screen. */ public static function render_dashboard_page() { include USECLICK_PLUGIN_DIR . 'templates/dashboard.php'; } /** * Links list screen. */ public static function render_links_page() { include USECLICK_PLUGIN_DIR . 'templates/links.php'; } /** * Countries offered for geo-targeting (ISO 3166-1 alpha-2). * * @return array */ public static function get_countries() { return array( 'US' => __( 'United States', 'useclick' ), 'GB' => __( 'United Kingdom', 'useclick' ), 'CA' => __( 'Canada', 'useclick' ), 'AU' => __( 'Australia', 'useclick' ), 'DE' => __( 'Germany', 'useclick' ), 'FR' => __( 'France', 'useclick' ), 'IT' => __( 'Italy', 'useclick' ), 'ES' => __( 'Spain', 'useclick' ), 'NL' => __( 'Netherlands', 'useclick' ), 'BE' => __( 'Belgium', 'useclick' ), 'CH' => __( 'Switzerland', 'useclick' ), 'AT' => __( 'Austria', 'useclick' ), 'SE' => __( 'Sweden', 'useclick' ), 'NO' => __( 'Norway', 'useclick' ), 'DK' => __( 'Denmark', 'useclick' ), 'FI' => __( 'Finland', 'useclick' ), 'PL' => __( 'Poland', 'useclick' ), 'CZ' => __( 'Czech Republic', 'useclick' ), 'HU' => __( 'Hungary', 'useclick' ), 'RO' => __( 'Romania', 'useclick' ), 'IE' => __( 'Ireland', 'useclick' ), 'PT' => __( 'Portugal', 'useclick' ), 'GR' => __( 'Greece', 'useclick' ), 'UA' => __( 'Ukraine', 'useclick' ), 'RU' => __( 'Russia', 'useclick' ), 'JP' => __( 'Japan', 'useclick' ), 'CN' => __( 'China', 'useclick' ), 'IN' => __( 'India', 'useclick' ), 'BR' => __( 'Brazil', 'useclick' ), 'MX' => __( 'Mexico', 'useclick' ), 'AR' => __( 'Argentina', 'useclick' ), 'CL' => __( 'Chile', 'useclick' ), 'CO' => __( 'Colombia', 'useclick' ), 'ZA' => __( 'South Africa', 'useclick' ), 'NG' => __( 'Nigeria', 'useclick' ), 'NZ' => __( 'New Zealand', 'useclick' ), 'SG' => __( 'Singapore', 'useclick' ), 'MY' => __( 'Malaysia', 'useclick' ), 'TH' => __( 'Thailand', 'useclick' ), 'ID' => __( 'Indonesia', 'useclick' ), 'PH' => __( 'Philippines', 'useclick' ), 'VN' => __( 'Vietnam', 'useclick' ), 'KR' => __( 'South Korea', 'useclick' ), 'TR' => __( 'Turkey', 'useclick' ), 'SA' => __( 'Saudi Arabia', 'useclick' ), 'AE' => __( 'United Arab Emirates', 'useclick' ), 'IL' => __( 'Israel', 'useclick' ), 'EG' => __( 'Egypt', 'useclick' ), ); } }