PluginProbe
Ultimate Cursor – Interactive and Animated Custom Cursor and Background Effects Toolkit / trunk
Ultimate Cursor – Interactive and Animated Custom Cursor and Background Effects Toolkit vtrunk
2.4.1 2.4.0 2.3.3 2.3.2 2.3.1 2.3.0 2.2.3 2.2.2 2.2.1 trunk 1.0.0 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 All 56 releases
ultimate-cursor / classes / class-admin.php

class-admin.php in Ultimate Cursor – Interactive and Animated Custom Cursor and Background Effects Toolkit trunk, at classes/class-admin.php

301 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin admin functions.
5 *
6 * @package ultimate-cursor
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Ultimate Cursor Admin class.
15 */
16 class Ultimate_Cursor_Admin {
17 /**
18 * The single class instance.
19 *
20 * @var $instance
21 */
22 private static $instance = null;
23
24 /**
25 * Get instance
26 */
27 public static function instance() {
28 if ( is_null( self::$instance ) ) {
29 self::$instance = new self();
30 }
31 return self::$instance;
32 }
33
34 /**
35 * Ultimate_Cursor_Admin constructor.
36 */
37 private function __construct() {
38 add_action( 'admin_init', array( $this, 'redirect_to_welcome_screen' ) );
39 add_action( 'admin_menu', array( $this, 'register_admin_menu' ), 20 );
40 add_action( 'in_admin_header', array( $this, 'disable_admin_notices' ), PHP_INT_MAX );
41
42 add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
43 // Enqueue media uploader
44 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_media_uploader' ) );
45
46 add_filter( 'plugin_action_links_ultimate-cursor/ultimate-cursor.php', array( $this, 'ultimate_cursor_settings_link' ) );
47 add_action( 'wp_ajax_ultimate_cursor_install_plugin', array( $this, 'ajax_install_plugin' ) );
48
49 // Registered on 'admin_init' (same hook the Freemius SDK uses for its own
50 // action links) — 'ultimate_cursor_fs_loaded' fires during 'plugins_loaded',
51 // too early to call __() without tripping the _load_textdomain_just_in_time notice.
52 add_action( 'admin_init', array( $this, 'add_promotional_action_link' ) );
53 }
54
55
56 public function disable_admin_notices() {
57 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Simple page check, not processing form data
58 if ( isset( $_GET['page'] ) && sanitize_text_field( wp_unslash( $_GET['page'] ) ) === 'ultimate-cursor' ) {
59 remove_all_actions( 'admin_notices' );
60 remove_all_actions( 'all_admin_notices' );
61 remove_all_actions( 'network_admin_notices' );
62 }
63 }
64 public function ultimate_cursor_settings_link( $links ) {
65 $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=ultimate-cursor&sub_page=settings' ) ) . '">' . esc_html__( 'Settings', 'ultimate-cursor' ) . '</a>';
66 array_unshift( $links, $settings_link );
67 return $links;
68 }
69
70 /**
71 * Add an "Upgrade to Pro" promotional link to the plugin's row actions on
72 * wp-admin/plugins.php, via the Freemius SDK so it merges correctly with
73 * the SDK's own action links. Styled inline since add_plugin_action_link()
74 * renders the label raw with no class hook to target from CSS.
75 */
76 public function add_promotional_action_link() {
77 if ( Ultimate_Cursor_License_Gate::is_premium_active() ) {
78 return;
79 }
80
81 $fs = ultimate_cursor_fs();
82 if ( ! $fs ) {
83 return;
84 }
85
86 // WP core's standard admin green — Freemius's own submenu "Upgrade" green
87 // (.fs-submenu-item.pricing.upgrade-mode, #adff2f) is tuned for the dark
88 // admin-menu background and washes out on the light plugin row here.
89 $label = '<span style="color:#00a32a;font-weight:600;">' . esc_html__( 'Upgrade to Pro', 'ultimate-cursor' ) . '</span>';
90
91 // Live pricing page, not $fs->get_upgrade_url() (that resolves to the local
92 // in-dashboard checkout URL). Mirrors Ultimate_Cursor_Dashboard_Widget::PRICING_URL —
93 // not referenced directly since that class isn't loaded when the pro plugin is active.
94 $fs->add_plugin_action_link(
95 $label,
96 esc_url( 'https://wpxero.com/plugins/ultimate-cursor/pricing' ),
97 true,
98 7,
99 'get-pro'
100 );
101 }
102
103 public function enqueue_media_uploader() {
104 // Only load the (heavy) media library JS on our own settings screen,
105 // not across the entire wp-admin.
106 $screen = get_current_screen();
107 if ( ! $screen || 'toplevel_page_ultimate-cursor' !== $screen->id ) {
108 return;
109 }
110 wp_enqueue_media();
111 }
112
113 public function ajax_install_plugin() {
114 check_ajax_referer( 'ultimate_cursor_admin_nonce', 'nonce' );
115
116 if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) {
117 wp_send_json_error( __( 'You do not have permission to install plugins.', 'ultimate-cursor' ) );
118 }
119
120 $slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
121 if ( empty( $slug ) ) {
122 wp_send_json_error( __( 'No plugin slug provided.', 'ultimate-cursor' ) );
123 }
124
125 include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
126 include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
127 include_once ABSPATH . 'wp-admin/includes/plugin.php';
128
129 // Check if already installed
130 $plugin_file = $this->get_plugin_file( $slug );
131
132 if ( ! $plugin_file ) {
133 // Needs installation
134 $api = plugins_api(
135 'plugin_information',
136 array(
137 'slug' => $slug,
138 'fields' => array( 'sections' => false ),
139 )
140 );
141 if ( is_wp_error( $api ) ) {
142 wp_send_json_error( $api->get_error_message() );
143 }
144
145 $status = install_plugin_install_status( $api );
146 if ( $status['status'] === 'install' || $status['status'] === 'update_available' ) {
147 $upgrader = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
148 $result = $upgrader->install( $api->download_link );
149 if ( is_wp_error( $result ) ) {
150 wp_send_json_error( $result->get_error_message() );
151 } elseif ( $result === false ) {
152 wp_send_json_error( __( 'Installation failed.', 'ultimate-cursor' ) );
153 }
154 }
155
156 // Find installed file
157 $plugin_file = $this->get_plugin_file( $slug );
158 }
159
160 if ( $plugin_file ) {
161 if ( ! is_plugin_active( $plugin_file ) ) {
162 $activate = activate_plugin( $plugin_file );
163 if ( is_wp_error( $activate ) ) {
164 wp_send_json_error( $activate->get_error_message() );
165 }
166 }
167 wp_send_json_success( array( 'message' => __( 'Plugin installed and activated successfully!', 'ultimate-cursor' ) ) );
168 }
169
170 wp_send_json_error( __( 'Could not locate the plugin file after installation.', 'ultimate-cursor' ) );
171 }
172
173 private function get_plugin_file( $slug ) {
174 require_once ABSPATH . 'wp-admin/includes/plugin.php';
175 $plugins = get_plugins();
176 foreach ( $plugins as $plugin_path => $plugin_data ) {
177 if ( strpos( $plugin_path, $slug . '/' ) === 0 ) {
178 return $plugin_path;
179 }
180 }
181 return false;
182 }
183
184 /**
185 * Redirect to Welcome page after activation.
186 */
187 public function redirect_to_welcome_screen() {
188 // Bail if no activation redirect.
189 if ( ! get_transient( '_ultimate_cursor_welcome_screen_activation_redirect' ) ) {
190 return;
191 }
192
193 // Delete the redirect transient.
194 delete_transient( '_ultimate_cursor_welcome_screen_activation_redirect' );
195
196 // Bail if activating from network, or bulk.
197 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
198 if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
199 return;
200 }
201
202 // Redirect to welcome page.
203 wp_safe_redirect( admin_url( 'admin.php?page=ultimate-cursor&sub_page=settings' ) );
204 exit;
205 }
206
207 /**
208 * Register admin menu.
209 *
210 * Add new Ultimate Cursor Settings admin menu.
211 */
212 public function register_admin_menu() {
213 if ( ! current_user_can( 'manage_options' ) ) {
214 return;
215 }
216
217 add_menu_page(
218 esc_html__( 'Ultimate Cursor', 'ultimate-cursor' ),
219 esc_html__( 'Ultimate Cursor', 'ultimate-cursor' ),
220 'manage_options',
221 'ultimate-cursor',
222 array( $this, 'print_admin_page' ),
223 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
224 'data:image/svg+xml;base64,' . base64_encode( file_get_contents( ultimate_cursor()->plugin_path . 'assets/images/admin-icon.svg' ) ),
225 '58.7'
226 );
227
228 // Labels intentionally match the in-app header navigation
229 // (src/admin/pages/index.js) so both menus read the same. The
230 // top-level slug IS the Cursors page (default once configured) —
231 // there is no separate Dashboard overview.
232 add_submenu_page(
233 'ultimate-cursor',
234 esc_html__( 'Cursors', 'ultimate-cursor' ),
235 esc_html__( 'Cursors', 'ultimate-cursor' ),
236 'manage_options',
237 'ultimate-cursor'
238 );
239 add_submenu_page(
240 'ultimate-cursor',
241 esc_html__( 'Background', 'ultimate-cursor' ),
242 esc_html__( 'Background', 'ultimate-cursor' ),
243 'manage_options',
244 'admin.php?page=ultimate-cursor&sub_page=background'
245 );
246 add_submenu_page(
247 'ultimate-cursor',
248 esc_html__( 'Support', 'ultimate-cursor' ),
249 esc_html__( 'Support', 'ultimate-cursor' ),
250 'manage_options',
251 'https://wordpress.org/support/plugin/ultimate-cursor/'
252 );
253 }
254
255 /**
256 * Print admin page.
257 */
258 public function print_admin_page() {
259 ?>
260 <div class="ultimate-cursor-admin-root"></div>
261 <?php
262 }
263
264 /**
265 * Add page class to body.
266 *
267 * @param string $classes - body classes.
268 */
269 public function admin_body_class( $classes ) {
270 $screen = get_current_screen();
271
272 if ( ! $screen || 'toplevel_page_ultimate-cursor' !== $screen->id ) {
273 return $classes;
274 }
275
276 $classes .= ' ultimate-cursor-admin-page';
277
278 // Sub page.
279 $page_name = 'welcome';
280
281 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Simple page check, not processing form data
282 if ( isset( $_GET['sub_page'] ) && sanitize_text_field( wp_unslash( $_GET['sub_page'] ) ) ) {
283 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Simple page check, not processing form data
284 $page_name = esc_attr( sanitize_text_field( wp_unslash( $_GET['sub_page'] ) ) );
285 }
286
287 $classes .= ' ultimate-cursor-admin-page-' . $page_name;
288
289 // Is first loading after plugin activation redirect.
290 // phpcs:ignore WordPress.Security.NonceVerification
291 if ( isset( $_GET['is_first_loading'] ) ) {
292 $classes .= ' ultimate-cursor-admin-first-loading';
293 }
294
295 return $classes;
296 }
297 }
298
299
300 Ultimate_Cursor_Admin::instance();
301