diff --git a/assets/css/jumper.css b/assets/css/jumper.css deleted file mode 100644 index 865f20b8..00000000 --- a/assets/css/jumper.css +++ /dev/null @@ -1,408 +0,0 @@ -#wu-jumper { - box-sizing: border-box; - position: fixed; - top: 25%; - left: 50%; - width: 500px; - margin-left: -250px; - background: #f9f9f9; - z-index: 99999; - border-radius: 5px; - border: solid 1px #ccc; - -webkit-box-shadow: 0 0 5000px 5000px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 0 5000px 5000px rgba(0, 0, 0, 0.2); - box-shadow: 0 0 5000px 5000px rgba(0, 0, 0, 0.2); - /* @group Base */ - /* @end */ - /* @group Single Chosen */ - /* @end */ - /* @group Results */ - /* @end */ - /* @group Multi Chosen */ - /* @end */ - /* @end */ - /* @group Disabled Support */ - /* @end */ - /* @group Retina compatibility */ - /* @end */ -} -#wu-jumper .wu-jumper-icon-container::before { - font-family: dashicons-wu, sans-serif !important; - content: "\e900"; - position: absolute; - top: 50%; - right: 15px; - font-size: 36px; - margin-top: -18px; - height: 36px; - line-height: 36px; -} -#wu-jumper * { - box-sizing: border-box; -} -#wu-jumper label { - display: block; - text-transform: uppercase; - padding: 20px; -} -#wu-jumper .selectize-control { - width: 100%; -} -#wu-jumper .wu-chosen-container { - position: relative; - display: inline-block; - vertical-align: middle; - font-size: 13px; - zoom: 1; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-drop { - margin-top: -1px; - border-radius: 0 0 4px 4px; - background-clip: padding-box; - border: solid 1px #ccc; - border-top: none; -} -#wu-jumper .wu-chosen-container .wu-chosen-drop { - position: absolute; - top: 100%; - left: -9999px; - z-index: 1010; - width: 100%; - border-top: 0; - background: #fff; -} -#wu-jumper .wu-chosen-container.wu-chosen-with-drop .wu-chosen-drop { - left: 0; -} -#wu-jumper .wu-chosen-container * { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -#wu-jumper .wu-chosen-container a { - cursor: pointer; -} -#wu-jumper .wu-chosen-container .search-choice .group-name, -#wu-jumper .wu-chosen-container .wu-chosen-single .group-name { - margin-right: 4px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - font-weight: normal; - color: #999; -} -#wu-jumper .wu-chosen-container .search-choice .group-name::after, -#wu-jumper .wu-chosen-container .wu-chosen-single .group-name::after { - content: ":"; - padding-left: 2px; - vertical-align: top; -} -#wu-jumper .selectize-control.single .selectize-input::after { - display: none !important; -} -#wu-jumper .selectize-dropdown { - margin-top: 0 !important; - background-color: #fcfcfc; - border: solid 1px #ddd; -} -#wu-jumper .selectize-input { - margin-bottom: -7px; - position: relative; - display: block; - overflow: hidden; - color: #444; - border: none; - box-shadow: none; - background: none; - text-decoration: none; - white-space: nowrap; - line-height: 70px; - padding: 0 15px; -} -#wu-jumper .selectize-input .item { - font-size: 18pt; -} -#wu-jumper .selectize-input input { - font-size: 18pt; -} -#wu-jumper .selectize-input.single::after { - display: none !important; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-default { - color: #999; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single span { - display: block; - overflow: hidden; - margin-right: 26px; - text-overflow: ellipsis; - white-space: nowrap; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single-with-deselect span { - margin-right: 38px; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single abbr { - position: absolute; - top: 6px; - right: 26px; - display: block; - width: 12px; - height: 12px; - font-size: 1px; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single abbr:hover { - background-position: -42px -10px; -} -#wu-jumper .wu-chosen-container-single.wu-chosen-disabled .wu-chosen-single abbr:hover { - background-position: -42px -10px; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single div { - position: absolute; - top: 0; - right: 0; - display: block; - width: 18px; - height: 100%; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-single div b { - display: block; - width: 100%; - height: 100%; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-search { - position: relative; - z-index: 1010; - margin: 0; - white-space: nowrap; -} -#wu-jumper .wu-chosen-container-single .wu-chosen-search input[type=text] { - margin: 0; - padding: 4px 20px 4px 5px; - width: 100%; - height: auto; - outline: 0; - box-shadow: none !important; - background-color: #fcfcfc; - border: none; - border-bottom: solid 1px #ddd; - border-top: solid 1px #ddd; - font-size: 1em; - font-family: sans-serif; - line-height: normal; - border-radius: 0; -} -#wu-jumper .wu-chosen-container-single.wu-chosen-container-single-nosearch .wu-chosen-search { - position: absolute; - left: -9999px; -} -#wu-jumper .wu-chosen-container .wu-chosen-results { - color: #444; - position: relative; - overflow-x: hidden; - overflow-y: auto; - margin: 0 4px 4px 0; - padding: 0 0 0 4px; - max-height: 240px; - -webkit-overflow-scrolling: touch; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li { - display: none; - margin: 0; - padding: 15px 6px; - list-style: none; - line-height: 15px; - word-wrap: break-word; - -webkit-touch-callout: none; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.active-result { - display: list-item; - cursor: pointer; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.disabled-result { - display: list-item; - color: #ccc; - cursor: default; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.highlighted { - color: #fff; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.no-results { - color: #777; - display: list-item; - background: #f4f4f4; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.group-result { - display: list-item; - font-weight: bold; - cursor: default; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li.group-option { - padding-left: 15px; -} -#wu-jumper .wu-chosen-container .wu-chosen-results li em { - font-style: normal; - text-decoration: underline; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices { - position: relative; - overflow: hidden; - margin: 0; - padding: 0 5px; - width: 100%; - height: auto !important; - height: 1%; - background-color: #fff; - cursor: text; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li { - float: left; - list-style: none; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-field { - margin: 0; - padding: 0; - white-space: nowrap; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-field input[type=text] { - margin: 1px 0; - padding: 0; - height: 25px; - outline: 0; - background: transparent !important; - color: #999; - font-size: 100%; - font-family: sans-serif; - line-height: normal; - border-radius: 0; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice { - position: relative; - margin: 3px 5px 3px 0; - padding: 3px 20px 3px 5px; - max-width: 100%; - border-radius: 3px; - background-color: #eee; - background-size: 100% 19px; - background-repeat: repeat-x; - background-clip: padding-box; - color: #333; - line-height: 13px; - cursor: default; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice span { - word-wrap: break-word; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice-focus .search-choice-close { - background-position: -42px -10px; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice .search-choice-close { - position: absolute; - top: 4px; - right: 3px; - display: block; - width: 12px; - height: 12px; - font-size: 1px; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice .search-choice-close:hover { - background-position: -42px -10px; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice-disabled { - padding-right: 5px; - background-color: #e4e4e4; - color: #666; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-choices li.search-choice-focus { - background: #d4d4d4; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-results { - margin: 0; - padding: 0; -} -#wu-jumper .wu-chosen-container-multi .wu-chosen-drop .result-selected { - display: list-item; - color: #ccc; - cursor: default; -} -#wu-jumper .wu-chosen-disabled .wu-chosen-single { - cursor: default; -} -#wu-jumper .wu-chosen-container-active.wu-chosen-with-drop .wu-chosen-single { - -moz-border-radius-bottomright: 0; - border-bottom-right-radius: 0; - -moz-border-radius-bottomleft: 0; - border-bottom-left-radius: 0; -} -#wu-jumper .wu-chosen-container-active.wu-chosen-with-drop .wu-chosen-single div { - border-left: none; - background: transparent; -} -#wu-jumper .wu-chosen-container-active.wu-chosen-with-drop .wu-chosen-single div b { - background-position: -18px 2px; -} -#wu-jumper .wu-chosen-container-active .wu-chosen-choices li.search-field input[type=text] { - color: #222 !important; -} -#wu-jumper .wu-chosen-disabled { - opacity: 0.5 !important; - cursor: default; -} -#wu-jumper .wu-chosen-disabled .wu-chosen-container-multi.wu-chosen-choices li.search-choice .search-choice-close { - cursor: default; -} -@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) { - #wu-jumper .wu-chosen-rtl .wu-chosen-search input[type=text], - #wu-jumper .wu-chosen-container-single .wu-chosen-single abbr, - #wu-jumper .wu-chosen-container-single .wu-chosen-single div b, - #wu-jumper .wu-chosen-container-single .wu-chosen-search input[type=text], - #wu-jumper .wu-chosen-container-multi .wu-chosen-choices .search-choice .search-choice-close, - #wu-jumper .wu-chosen-container .wu-chosen-results-scroll-down span, - #wu-jumper .wu-chosen-container .wu-chosen-results-scroll-up span { - background-size: 52px 37px !important; - background-repeat: no-repeat !important; - } -} - -#wu_jumper_select_chosen { /* stylelint-disable-line selector-id-pattern */ - margin: 0; - width: 100% !important; - padding: 0; -} - -#wu_jumper_select_chosen input { /* stylelint-disable-line selector-id-pattern */ - outline: none; - width: 100%; - padding: 20px !important; -} - -span.wu-keys { - margin-right: 20px; -} - -span.wu-keys-key { - display: inline-block; - padding: 0 5px 1px; - border: solid 2px #999; - border-radius: 3px; - margin: 0 2px; -} - -.wu-jumper-loading, -.wu-jumper-redirecting { - border-top: solid 1px #cecece; - padding: 10px; - text-align: center; - display: none; -} - -body.rtl #wu-jumper .wu-chosen-container-single .wu-chosen-single::after { - right: auto; - left: 15px; -} -body.rtl #wu-jumper .wu-chosen-container-single .wu-chosen-single span { - margin-right: 0; - margin-left: 26px; -} \ No newline at end of file diff --git a/assets/js/command-palette.js b/assets/js/command-palette.js index 86356908..04a56a5f 100644 --- a/assets/js/command-palette.js +++ b/assets/js/command-palette.js @@ -286,7 +286,7 @@ label: entity.label_plural || entity.label + 's', callback: ({ close }) => { close(); - window.location.href = networkAdminUrl + 'admin.php?page=wu-' + slug.replace(/_/g, '-') + 's'; + window.location.href = networkAdminUrl + 'admin.php?page=wu-' + slug.replaceAll('_', '-') + 's'; } }; diff --git a/assets/js/jumper.js b/assets/js/jumper.js deleted file mode 100644 index a9ed0067..00000000 --- a/assets/js/jumper.js +++ /dev/null @@ -1,165 +0,0 @@ -/* eslint-disable no-undef */ -(function($) { - - $(document).ready(function() { - - // Adds WUChosen.js to our custom select input - const $jumper = $('#wu-jumper-select').selectize({ - create: false, - maxItems: 1, - optgroupField: 'group', - optgroupValueField: 'value', - searchField: ['text', 'name', 'display_name', 'domain', 'title', 'desc', 'code'], - render: { - option(option) { - - if (typeof option.model === 'undefined') { - - option.model = 'jumper-link'; - - } // end if; - - if (typeof option.text === 'undefined') { - - option.text = option.reference_code || option.name || option.title || option.display_name || option.code; - - } // end if; - - if (typeof option.group === 'undefined') { - - option.group = option.model; - - } // end if; - - const template_html = jQuery('#wu-template-' + option.model).length ? - jQuery('#wu-template-' + option.model).html() : - jQuery('#wu-template-default').html(); - - const template = _.template(template_html, { - interpolate: /\{\{(.+?)\}\}/g, - }); - - return template(option); - - }, - }, - load(query, callback) { - - if (! query.length) { - - return callback(); - - } // end if; - - $('#wu-jumper .wu-jumper-loading').show(); - - jQuery.ajax({ - // eslint-disable-next-line no-undef - url: wu_jumper_vars.ajaxurl, - type: 'POST', - data: { - action: 'wu_search', - model: 'all', - number: 99, - query: { - search: '*' + query + '*', - }, - }, - error() { - - callback(); - - }, - success(res) { - - $('#wu-jumper .wu-jumper-loading').hide(); - - callback(res); - - }, - }); - - }, - }); - - const is_local_url = function(url) { - - return url.toLowerCase().indexOf(wu_jumper_vars.base_url) >= 0 || url.toLowerCase().indexOf(wu_jumper_vars.network_base_url) >= 0; - - }; // end is_local_url - - // Every time the value changes, we need to redirect the user - $jumper.on('change', function() { - - // Check if we need to open this in a new tab - if (is_local_url($(this).val())) { - - window.location.href = $(this).val(); - - $(this).parent().parent().find('.wu-jumper-redirecting').show(); - - } else { - - window.open($(this).val(), '_blank'); - - $($jumper.parent()).hide(); - - } // end if; - - }); - - // Closes on clicking other elements - $(document).on('click', ':not(#wu-jumper-button-trigger)', function(e) { - - const target = e.target; - - if ($(target).attr('id') === 'wu-jumper-button-trigger' || $(target).parent().attr('id') === 'wu-jumper-button-trigger') { - - return; - - } // end if; - - if (! $(target).is($jumper.parent()) && ! $(target).parents().is($jumper.parent())) { - - $($jumper.parent().parent()).hide(); - - } // end if; - - }); - - const trigger_key = wu_jumper_vars.trigger_key.charAt(0); - - // Our bar is hidden by default, we need to display it when a certain shortcut is pressed - Mousetrap.bind(['command+option+' + trigger_key, 'ctrl+alt+' + trigger_key], function(e) { - - e.preventDefault(); - - open_jumper(); - - }); // end mousetrap; - - $(document).on('click', '#wu-jumper-button-trigger', function(e) { - - e.preventDefault(); - - open_jumper(); - - }); - - /** - * Actually opens the jumper. - */ - function open_jumper() { - - $('#wu-jumper').show(); - - $('#wu-jumper').find('input').focus(); - - return false; - - } // end open_jumper; - - }); - -}(jQuery)); - diff --git a/inc/class-ajax.php b/inc/class-ajax.php index 1b621e80..0af45ac0 100644 --- a/inc/class-ajax.php +++ b/inc/class-ajax.php @@ -27,16 +27,6 @@ class Ajax implements \WP_Ultimo\Interfaces\Singleton { * @since 2.0.0 */ public function init(): void { - /* - * Load search endpoints. - */ - add_action('wu_ajax_wu_search', [$this, 'search_models']); - - /* - * Adds the Selectize templates to the admin_footer. - */ - add_action('in_admin_footer', [$this, 'render_selectize_templates']); - /* * Load search endpoints. */ @@ -77,371 +67,4 @@ public function refresh_list_table(): void { do_action('wu_list_table_fetch_ajax_results', $table_id); } - - /** - * Search models using our ajax endpoint. - * - * @since 2.0.0 - * @return void - */ - public function search_models(): void { - - /** - * Fires before the processing of the search request. - * - * @since 2.0.0 - */ - do_action('wu_before_search_models'); - - if (wu_request('model') === 'all') { - $this->search_all_models(); - - return; - } - - $args = wp_parse_args( - $_REQUEST, // phpcs:ignore WordPress.Security.NonceVerification.Recommended - [ - 'model' => 'membership', - 'query' => [], - 'number' => 100, - 'exclude' => [], // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude - ] - ); - - // Number can be in the query array or it's own. Code uses both. - if (empty($args['query']['number'])) { - $args['query']['number'] = $args['number']; - } - - if ($args['exclude']) { - if (is_string($args['exclude'])) { - $args['exclude'] = explode(',', $args['exclude']); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude - - $args['exclude'] = array_map('trim', $args['exclude']); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude - } - - $query['id__not_in'] = $args['exclude']; - } - - if (wu_get_isset($args, 'include')) { - if (is_string($args['include'])) { - $args['include'] = explode(',', $args['include']); - - $args['include'] = array_map('trim', $args['include']); - } - - $query['id__in'] = $args['include']; - } - - /* - * Deal with site - */ - if ('site' === $args['model']) { - if (wu_get_isset($query, 'id__in')) { - $query['blog_id__in'] = $query['id__in']; - - unset($query['id__in']); - } - - if (wu_get_isset($query, 'id__not_in')) { - $query['blog_id__not_in'] = $query['id__not_in']; - - unset($query['id__not_in']); - } - } - - $results = []; - - // Merge the caller's query params (search term, etc.) with locally-built params. - $query = array_merge($args['query'], $query ?? []); - - if ('user' === $args['model']) { - $results = $this->search_wordpress_users($query); - } elseif ('page' === $args['model']) { - $results = get_posts( - [ - 'post_type' => 'page', - 'post_status' => 'publish', - 'numberposts' => -1, - 'exclude' => $query['id__not_in'] ?? '', // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude - ] - ); - } elseif ('setting' === $args['model']) { - $results = $this->search_wp_ultimo_setting($query); - } else { - $model_func = 'wu_get_' . strtolower((string) $args['model']) . 's'; - - if (function_exists($model_func)) { - $results = $model_func($query); - } - } - - // Try search by hash if do not have any result - if (empty($results)) { - $model_func = 'wu_get_' . strtolower((string) $args['model']) . '_by_hash'; - - if (function_exists($model_func)) { - $result = $model_func(trim((string) $query['search'], '*')); - - $results = $result ? [$result] : []; - } - } - - wp_send_json($results); - - exit; - } - - /** - * Search all models for Jumper. - * - * @since 2.0.0 - * @return void - */ - public function search_all_models(): void { - - $query = array_merge( - wu_request('query', []), - [ - 'number' => 10000, - ] - ); - - $results_user = array_map( - function ($item) { - - $item->model = 'user'; - - $item->group = 'Users'; - - $item->value = network_admin_url("user-edit.php?user_id={$item->ID}"); - - return $item; - }, - $this->search_wordpress_users($query) - ); - - $results_settings = array_map( - function ($item) { - - $item['model'] = 'setting'; - - $item['group'] = 'Settings'; - - $item['value'] = $item['url']; - - return $item; - }, - $this->search_wp_ultimo_setting($query) - ); - - $data = array_merge($results_user, $results_settings); - - /** - * Allow plugin developers to add more search models functions. - * - * @since 2.0.0 - */ - $data_sources = apply_filters( - 'wu_search_models_functions', - [ - 'wu_get_customers', - 'wu_get_products', - 'wu_get_plans', - 'wu_get_domains', - 'wu_get_sites', - 'wu_get_memberships', - 'wu_get_payments', - 'wu_get_broadcasts', - 'wu_get_checkout_forms', - ] - ); - - foreach ($data_sources as $function) { - $results = call_user_func($function, $query); - - $results = array_map( - function ($item) { - - $row = $item->to_array(); - - $url = str_replace('_', '-', (string) $row['model']); - - $row['value'] = wu_network_admin_url( - "wp-ultimo-edit-{$url}", - [ - 'id' => $item->get_id(), - ] - ); - - $row['group'] = ucwords((string) $row['model']) . 's'; - - return $row; - }, - $results - ); - - $discount_codes = array_map( - function ($item) { - - $discount = $item->to_array(); - - $discount['value'] = wu_network_admin_url( - 'wp-ultimo-edit-discount-code', - [ - 'id' => $discount['id'], - ] - ); - - $discount['group'] = 'Discount Codes'; - - return $discount; - }, - wu_get_discount_codes($query) - ); - - $data = array_merge($data, $results, $discount_codes); - } - - wp_send_json($data); - } - - /** - * Search for Ultimate Multisite settings to help customers find them. - * - * @since 2.0.0 - * - * @param array $query Query arguments. - */ - public function search_wp_ultimo_setting($query): array { - - $sections = \WP_Ultimo\Settings::get_instance()->get_sections(); - - $all_fields = []; - - foreach ($sections as $section_slug => $section) { - $section['fields'] = array_map( - function ($item) use ($section, $section_slug) { - - $item['section'] = $section_slug; - - $item['section_title'] = wu_get_isset($section, 'title', ''); - - $item['url'] = wu_network_admin_url( - 'wp-ultimo-settings', - [ - 'tab' => $section_slug, - ] - ) . '#' . $item['setting_id']; - - return $item; - }, - $section['fields'] - ); - - $all_fields = array_merge($all_fields, $section['fields']); - } - - $search_term = strtolower(trim((string) $query['search'], '*')); - - /* - * Filter settings that match the search term against setting_id, title, - * or desc fields (case-insensitive), excluding header-type fields. - * The previous implementation only searched setting_id, which meant users - * could not find settings by their human-readable titles. - */ - $_settings = array_filter( - $all_fields, - function ($item) use ($search_term) { - - if (wu_get_isset($item, 'type') === 'header') { - return false; - } - - $setting_id = strtolower((string) wu_get_isset($item, 'setting_id', '')); - $title = strtolower((string) wu_get_isset($item, 'title', '')); - $desc = strtolower((string) wu_get_isset($item, 'desc', '')); - - return str_contains($setting_id, $search_term) - || str_contains($title, $search_term) - || str_contains($desc, $search_term); - } - ); - - usort( - $_settings, - function ($a, $b) { - - return strcmp( - (string) wu_get_isset($a, 'title', ''), - (string) wu_get_isset($b, 'title', '') - ); - } - ); - - return array_values($_settings); - } - - /** - * Handles the special case of searching native WP users. - * - * @since 2.0.0 - * - * @param array $query Query arguments. - * @return array - */ - public function search_wordpress_users($query) { - - $results = get_users( - [ - 'blog_id' => 0, - 'search' => '*' . $query['search'] . '*', - 'search_columns' => [ - 'ID', - 'user_login', - 'user_email', - 'user_url', - 'user_nicename', - 'display_name', - ], - ] - ); - - $results = array_map( - function ($item) { - - $item->data->user_pass = ''; - - $item->data->avatar = get_avatar( - $item->data->user_email, - 40, - 'identicon', - '', - [ - 'force_display' => true, - 'class' => 'wu-rounded-full wu-mr-3', - ] - ); - - return $item->data; - }, - $results - ); - - return $results; - } - - /** - * Adds the selectize templates to the admin footer. - * - * @since 2.0.0 - * @return void - */ - public function render_selectize_templates(): void { - - if (current_user_can('manage_network')) { - wu_get_template('ui/selectize-templates'); - } - } } diff --git a/inc/ui/class-jumper.php b/inc/ui/class-jumper.php deleted file mode 100644 index 298201b5..00000000 --- a/inc/ui/class-jumper.php +++ /dev/null @@ -1,570 +0,0 @@ - $page, - 'jumper' => $this, - ] - ); - } - - /** - * Loads the necessary elements to display the Jumper. - * - * @since 2.0.0 - * @return void - */ - public function load_jumper(): void { - - if ($this->is_jumper_enabled() && is_admin()) { - add_action('wu_header_right', [$this, 'add_jumper_trigger']); - - add_action('admin_init', [$this, 'rebuild_menu']); - - add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']); - - add_action('admin_enqueue_scripts', [$this, 'enqueue_styles']); - - add_action('admin_footer', [$this, 'output']); - - add_filter('update_footer', [$this, 'add_jumper_footer_message'], 200); - - add_action('wu_after_save_settings', [$this, 'clear_jump_cache_on_save']); - - add_filter('wu_link_list', [$this, 'add_wp_ultimo_extra_links']); - - add_filter('wu_link_list', [$this, 'add_user_custom_links']); - } - } - - /** - * Clear the jumper menu cache on settings save - * - * We need to do this to make sure that we clear the menu when the admin - * adds a new custom menu item. - * - * @since 2.0.0 - * - * @param array $settings Settings being saved. - * @return void - */ - public function clear_jump_cache_on_save($settings): void { - - if (isset($settings['jumper_custom_links'])) { - delete_site_transient($this->transient_key); - } - } - - /** - * Rebuilds the jumper menu via a trigger URL. - * - * @since 2.0.0 - * @return void - */ - public function rebuild_menu(): void { - - if (isset($_GET[ $this->reset_slug ]) && isset($_GET['nonce']) && current_user_can('manage_network') && wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'reset_password')) { - delete_site_transient($this->transient_key); - - wp_safe_redirect(network_admin_url()); - - exit; - } - } - - /** - * Retrieves the custom links added by the super admin - * - * @since 2.0.0 - * @return array - */ - public function get_user_custom_links() { - - $treated_lines = []; - - $saved_links = wu_get_setting('jumper_custom_links', ''); - - $lines = explode(PHP_EOL, (string) $saved_links); - - foreach ($lines as $line) { - $link_elements = explode(':', $line, 2); - - if (count($link_elements) === 2) { - $title = trim($link_elements[1]); - - $treated_lines[ $title ] = trim($link_elements[0]); - } - } - - return $treated_lines; - } - - /** - * Add the custom links to the Jumper menu - * - * @since 2.0.0 - * - * @param array $links Jumper links already saved. - * @return array - */ - public function add_user_custom_links($links) { - - $custom_links = $this->get_user_custom_links(); - - if ( ! empty($custom_links)) { - $links[ __('Custom Links', 'ultimate-multisite') ] = $custom_links; - } - - return $links; - } - - /** - * Add Ultimate Multisite settings links to the Jumper menu. - * - * @since 2.0.0 - * - * @param array $links Ultimate Multisite settings array. - * @return array - */ - public function add_wp_ultimo_extra_links($links) { - - if (isset($links['WP Ultimo'])) { - $settings_tabs = [ - 'general' => __('General', 'ultimate-multisite'), - 'network' => __('Network Settings', 'ultimate-multisite'), - 'gateways' => __('Payment Gateways', 'ultimate-multisite'), - 'domain_mapping' => __('Domain Mapping & SSL', 'ultimate-multisite'), - 'emails' => __('Emails', 'ultimate-multisite'), - 'styling' => __('Styling', 'ultimate-multisite'), - 'tools' => __('Tools', 'ultimate-multisite'), - 'advanced' => __('Advanced', 'ultimate-multisite'), - 'activation' => __('Activation & Support', 'ultimate-multisite'), - ]; - - foreach ($settings_tabs as $tab => $tab_label) { - $url = network_admin_url('admin.php?page=wp-ultimo-settings&wu-tab=' . $tab); - - // translators: The placeholder represents the title of the Settings tab. - $links['WP Ultimo'][ $url ] = sprintf(__('Settings: %s', 'ultimate-multisite'), $tab_label); - } - - $links['WP Ultimo'][ network_admin_url('admin.php?page=wp-ultimo-settings&wu-tab=tools') ] = __('Settings: Webhooks', 'ultimate-multisite'); - - $links['WP Ultimo'][ network_admin_url('admin.php?page=wp-ultimo-system-info&wu-tab=logs') ] = __('System Info: Logs', 'ultimate-multisite'); - - /** - * Adds Main Site Dashboard - */ - if (isset($links[ __('Sites') ])) { // phpcs:ignore WordPress.WP.I18n.MissingArgDomain - $main_site_url = get_admin_url(get_current_site()->site_id); - - $links[ __('Sites') ][ $main_site_url ] = __('Main Site Dashboard', 'ultimate-multisite'); // phpcs:ignore WordPress.WP.I18n.MissingArgDomain - } - } - - return $links; - } - - /** - * Get the trigger key defined by the user. - * - * @since 2.0.0 - */ - public function get_defined_trigger_key(): string { - - return substr((string) wu_get_setting('jumper_key', 'g'), 0, 1); - } - - /** - * Get the trigger key combination depending on the OS - * - * - For Win & Linux: ctrl + alt + key defined by user; - * - For Mac: command + option + key defined by user. - * - * @since 2.0.0 - * - * @param string $os OS to get the key combination for. Options: win or osx. - * @return array - */ - public function get_keys($os = 'win') { - - $trigger_key = $this->get_defined_trigger_key(); - - $keys = [ - 'win' => ['ctrl', 'alt', $trigger_key], - 'osx' => ['command', 'option', $trigger_key], - ]; - - return $keys[ $os ] ?? $keys['win']; - } - - /** - * Changes the helper footer message about the Jumper and its trigger - * - * @since 2.0.0 - * - * @param string $text The default WordPress right footer message. - * @return string - */ - public function add_jumper_footer_message($text) { - - if ( ! wu_get_setting('jumper_display_tip', true)) { - return $text; - } - - $os = isset($_SERVER['HTTP_USER_AGENT']) && stristr(sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])), 'mac') ? 'osx' : 'win'; - - $keys = $this->get_keys($os); - - $html = ''; - - foreach ($keys as $key) { - $html .= '' . $key . '+'; - } - - $html = trim($html, '+'); - - // translators: the %s placeholder is the key combination to trigger the Jumper. - return '' . sprintf(__('Quick Tip: Use %s to jump between pages.', 'ultimate-multisite'), $html) . '' . $text; - } - - /** - * Enqueues the JavaScript files necessary to make the jumper work. - * - * @since 2.0.0 - * @return void - */ - public function enqueue_scripts(): void { - - wp_register_script('wu-mousetrap', wu_get_asset('mousetrap.js', 'js/lib'), ['jquery'], wu_get_version(), true); - - wp_register_script('wu-jumper', wu_get_asset('jumper.js', 'js'), ['jquery', 'wu-selectize', 'wu-mousetrap', 'underscore'], wu_get_version(), true); - - wp_localize_script( - 'wu-jumper', - 'wu_jumper_vars', - [ - 'not_found_message' => __('Nothing found for', 'ultimate-multisite'), - 'trigger_key' => $this->get_defined_trigger_key(), - 'network_base_url' => network_admin_url(), - 'ajaxurl' => wu_ajax_url(), - 'base_url' => get_admin_url(get_current_site()->site_id), - ] - ); - - wp_enqueue_script('wu-jumper'); - - wp_enqueue_style('wu-admin'); - } - - /** - * Enqueues the CSS files necessary to make the jumper work. - * - * @since 2.0.0 - * @return void - */ - public function enqueue_styles(): void { - - wp_enqueue_style('wu-jumper', wu_get_asset('jumper.css', 'css'), [], wu_get_version()); - } - - /** - * Outputs the actual HTML markup of the Jumper. - * - * @since 2.0.0 - * @return void - */ - public function output(): void { - - wu_get_template( - 'ui/jumper', - [ - 'menu_groups' => $this->get_link_list(), - ] - ); - } - - /** - * Get the full page URL for admin pages. - * - * @since 2.0.0 - * - * @param string $url URL of the menu item. - */ - public function get_menu_page_url($url): string { - - $final_url = menu_page_url($url, false); - - return str_replace(admin_url(), network_admin_url(), $final_url); - } - - /** - * Returns the URL of a jumper menu item - * - * If the URL is an absolute URL, returns the full-url. - * If the URL is relative, we return the full URL using WordPress url functions. - * - * @since 2.0.0 - * - * @param string $url URL of the menu item. - * @return string - */ - public function get_target_url($url) { - - if (str_contains($url, 'http')) { - return $url; - } - - if (str_contains($url, '.php')) { - return network_admin_url($url); - } - - return $this->get_menu_page_url($url); - } - - /** - * Builds the list of links based on the $menu and $submenu globals. - * - * @since 2.0.0 - * - * @return array - */ - public function build_link_list() { - - return Logger::track_time( - 'jumper', - __('Regenerating Jumper menu items', 'ultimate-multisite'), - function () { - - global $menu, $submenu; - - // This variable is going to carry our options - $choices = []; - - // Prevent first run bug - if ( ! is_array($menu) || ! is_array($submenu)) { - return []; - } - - // Loop all submenus so que can get our final - foreach ($submenu as $menu_name => $submenu_items) { - $title = $this->search_recursive($menu_name, $menu); - - $string = wu_get_isset($title, 0, ''); - - $title = preg_replace('/[0-9]+/', '', wp_strip_all_tags($string)); - - // If parent does not exists, skip - if ( ! empty($title) && is_array($submenu_items)) { - - // We have to loop now each submenu - foreach ($submenu_items as $submenu_item) { - $url = $this->get_target_url($submenu_item[2]); - - // Add to our choices the admin urls - } - } - } - - $choices = apply_filters('wu_link_list', $choices); - - set_site_transient($this->transient_key, $choices, 10 * MINUTE_IN_SECONDS); - - return $choices; - } - ); - } - - /** - * Gets the cached menu list saved. - * - * @since 2.0.0 - * @return array - */ - public function get_saved_menu() { - - $saved_menu = get_site_transient($this->transient_key); - - return $saved_menu ?: []; - } - - /** - * Returns the link list. - * - * @since 2.0.0 - * @return array - */ - public function get_link_list() { - - $should_rebuild_menu = ! get_site_transient($this->transient_key); - - return $should_rebuild_menu && is_network_admin() ? $this->build_link_list() : $this->get_saved_menu(); - } - - /** - * Filter the Ultimate Multisite settings to add Jumper options - * - * @since 2.0.0 - * - * @return void - */ - public function add_settings(): void { - - wu_register_settings_section( - 'tools', - [ - 'title' => __('Tools', 'ultimate-multisite'), - 'desc' => __('Tools', 'ultimate-multisite'), - 'icon' => 'dashicons-wu-tools', - ] - ); - - wu_register_settings_field( - 'tools', - 'tools_header', - [ - 'title' => __('Jumper', 'ultimate-multisite'), - 'desc' => __('Spotlight-like search bar that allows you to easily access everything on your network.', 'ultimate-multisite'), - 'type' => 'header', - ] - ); - - wu_register_settings_field( - 'tools', - 'enable_jumper', - [ - 'title' => __('Enable Jumper', 'ultimate-multisite'), - 'desc' => __('Turn this option on to make the Jumper available on your network.', 'ultimate-multisite'), - 'type' => 'toggle', - 'default' => 1, - ] - ); - - wu_register_settings_field( - 'tools', - 'jumper_key', - [ - 'title' => __('Trigger Key', 'ultimate-multisite'), - 'desc' => __('Change the keyboard key used in conjunction with ctrl + alt (or cmd + option), to trigger the Jumper box.', 'ultimate-multisite'), - 'type' => 'text', - 'default' => 'g', - 'require' => [ - 'enable_jumper' => 1, - ], - ] - ); - - wu_register_settings_field( - 'tools', - 'jumper_custom_links', - [ - 'title' => __('Custom Links', 'ultimate-multisite'), - 'desc' => __('Use this textarea to add custom links to the Jumper. Add one per line, with the format "Title : url".', 'ultimate-multisite'), - 'placeholder' => __('Tile of Custom Link : http://link.com', 'ultimate-multisite'), - 'type' => 'textarea', - 'html_attr' => [ - 'rows' => 4, - ], - 'require' => [ - 'enable_jumper' => 1, - ], - ] - ); - } - - /** - * Helper function to recursively seach an array. - * - * @since 2.0.0 - * - * @param string $needle String to seach recursively. - * @param array $haystack Array to search. - * @return mixed - */ - public function search_recursive($needle, $haystack) { - - foreach ($haystack as $key => $value) { - $current_key = $key; - - if ($needle === $value || (is_array($value) && $this->search_recursive($needle, $value) !== false)) { - return $value; - } - } - - return false; - } -}