| 1 |
<?php |
| 2 |
/** |
| 3 |
* Menu handler for SureCookie plugin. |
| 4 |
* |
| 5 |
* @package SureCookie |
| 6 |
* @subpackage SureCookie\Admin |
| 7 |
* @since 0.0.1 |
| 8 |
*/ |
| 9 |
|
| 10 |
namespace SureCookie\Admin; |
| 11 |
|
| 12 |
use SureCookie\Inc\Database\ConsentLog; |
| 13 |
use SureCookie\Inc\Functions\Get; |
| 14 |
use SureCookie\Inc\Functions\Helper; |
| 15 |
use SureCookie\Inc\Functions\Sanitize; |
| 16 |
use SureCookie\Inc\Functions\Settings; |
| 17 |
use SureCookie\Inc\Traits\GetInstance; |
| 18 |
use SureCookie\Inc\Utils\LocalizeData; |
| 19 |
|
| 20 |
defined( 'ABSPATH' ) || exit; |
| 21 |
|
| 22 |
/** |
| 23 |
* Menu handler for SureCookie plugin. |
| 24 |
* |
| 25 |
* This class handles the registration and rendering of the admin menu. |
| 26 |
* |
| 27 |
* @since 0.0.1 |
| 28 |
*/ |
| 29 |
class Menu { |
| 30 |
use GetInstance; |
| 31 |
|
| 32 |
/** |
| 33 |
* Admin page hooks that render the SureCookie app. |
| 34 |
* |
| 35 |
* @since 1.4.0 |
| 36 |
*/ |
| 37 |
private const PLUGIN_SCREEN_HOOKS = [ |
| 38 |
'toplevel_page_surecookie', |
| 39 |
'settings_page_surecookie', |
| 40 |
'surecookie_page_surecookie-banner', |
| 41 |
'surecookie_page_surecookie-settings', |
| 42 |
'surecookie_page_surecookie-advanced', |
| 43 |
]; |
| 44 |
|
| 45 |
/** |
| 46 |
* Constructor. |
| 47 |
* |
| 48 |
* @since 0.0.1 |
| 49 |
*/ |
| 50 |
public function __construct() { |
| 51 |
add_action( 'admin_menu', [ $this, 'register_admin_menu' ] ); |
| 52 |
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_assets' ] ); |
| 53 |
// Late, so it wins over plugins that enqueue on the default priority. |
| 54 |
add_action( 'admin_enqueue_scripts', [ $this, 'dequeue_conflicting_styles' ], 999 ); |
| 55 |
add_filter( 'plugin_action_links_' . SURECOOKIE_BASE, [ $this, 'plugin_action_links' ] ); |
| 56 |
|
| 57 |
if ( ! Helper::is_pro_active() && Settings::get( 'top_level_menu_enabled' ) ) { |
| 58 |
add_action( 'admin_footer', [ $this, 'print_upgrade_submenu_assets' ] ); |
| 59 |
} |
| 60 |
} |
| 61 |
|
| 62 |
/** |
| 63 |
* Register the admin menu. |
| 64 |
* |
| 65 |
* @since 0.0.1 |
| 66 |
* @return void |
| 67 |
*/ |
| 68 |
public function register_admin_menu(): void { |
| 69 |
$show_top_level = Settings::get( 'top_level_menu_enabled' ); |
| 70 |
|
| 71 |
if ( $show_top_level ) { |
| 72 |
// Resolve the unread-logs count once so the top-level attention dot |
| 73 |
// and the Logs submenu badge stay in sync from a single lookup. |
| 74 |
$unread_logs = $this->get_unread_logs_count(); |
| 75 |
|
| 76 |
add_menu_page( |
| 77 |
'SureCookie', |
| 78 |
$this->get_top_level_menu_title( $unread_logs ), |
| 79 |
SURECOOKIE_CAPABILITY, |
| 80 |
SURECOOKIE_PREFIX, |
| 81 |
[ $this, 'render_admin_page' ], |
| 82 |
'none', |
| 83 |
58 |
| 84 |
); |
| 85 |
|
| 86 |
$submenus = [ |
| 87 |
[ |
| 88 |
'id' => SURECOOKIE_PREFIX, |
| 89 |
'page_title' => __( 'Dashboard', 'surecookie' ), |
| 90 |
], |
| 91 |
[ |
| 92 |
'id' => SURECOOKIE_PREFIX . '#/cookie-manager/scan', |
| 93 |
'page_title' => __( 'Tracking Manager', 'surecookie' ), |
| 94 |
], |
| 95 |
[ |
| 96 |
'id' => SURECOOKIE_PREFIX . '#/analytics', |
| 97 |
'page_title' => __( 'Consent Logs', 'surecookie' ), |
| 98 |
'menu_title' => $this->get_logs_submenu_title( $unread_logs ), |
| 99 |
], |
| 100 |
[ |
| 101 |
'id' => SURECOOKIE_PREFIX . '#/data-requests', |
| 102 |
'page_title' => __( 'Data Requests', 'surecookie' ), |
| 103 |
'menu_title' => $this->get_data_requests_submenu_title( $this->get_open_data_requests_count() ), |
| 104 |
], |
| 105 |
[ |
| 106 |
'id' => SURECOOKIE_PREFIX . '#/banner/content', |
| 107 |
'page_title' => __( 'Settings', 'surecookie' ), |
| 108 |
], |
| 109 |
[ |
| 110 |
'id' => SURECOOKIE_PREFIX . '#/learn', |
| 111 |
'page_title' => __( 'Learn', 'surecookie' ), |
| 112 |
], |
| 113 |
]; |
| 114 |
|
| 115 |
foreach ( $submenus as $submenu ) { |
| 116 |
add_submenu_page( |
| 117 |
SURECOOKIE_PREFIX, |
| 118 |
$submenu['page_title'], |
| 119 |
$submenu['menu_title'] ?? $submenu['page_title'], |
| 120 |
SURECOOKIE_CAPABILITY, |
| 121 |
$submenu['id'], |
| 122 |
[ $this, 'render_admin_page' ] |
| 123 |
); |
| 124 |
} |
| 125 |
|
| 126 |
if ( ! Helper::is_pro_active() ) { |
| 127 |
$this->register_upgrade_submenu(); |
| 128 |
} |
| 129 |
|
| 130 |
return; |
| 131 |
} |
| 132 |
|
| 133 |
add_options_page( |
| 134 |
'SureCookie', |
| 135 |
'SureCookie', |
| 136 |
SURECOOKIE_CAPABILITY, |
| 137 |
SURECOOKIE_PREFIX, |
| 138 |
[ $this, 'render_admin_page' ] |
| 139 |
); |
| 140 |
} |
| 141 |
|
| 142 |
/** |
| 143 |
* Render the admin page. |
| 144 |
* |
| 145 |
* @since 0.0.1 |
| 146 |
* @return void |
| 147 |
*/ |
| 148 |
public function render_admin_page(): void { |
| 149 |
if ( ! current_user_can( SURECOOKIE_CAPABILITY ) ) { |
| 150 |
wp_die( esc_html__( 'You don\'t have access to this page.', 'surecookie' ) ); |
| 151 |
} |
| 152 |
|
| 153 |
echo '<div class="wrap">'; |
| 154 |
echo '<div id="surecookie-admin-root"></div>'; |
| 155 |
echo '</div>'; |
| 156 |
} |
| 157 |
|
| 158 |
/** |
| 159 |
* Enqueue admin assets. |
| 160 |
* |
| 161 |
* @since 0.0.1 |
| 162 |
* @param string $hook The current admin page. |
| 163 |
* @return void |
| 164 |
*/ |
| 165 |
public function enqueue_admin_assets( $hook ): void { |
| 166 |
$this->enqueue_admin_menu_icon_style(); |
| 167 |
|
| 168 |
if ( ! in_array( $hook, self::PLUGIN_SCREEN_HOOKS, true ) ) { |
| 169 |
return; |
| 170 |
} |
| 171 |
|
| 172 |
$asset_file = SURECOOKIE_DIR . 'build/admin.asset.php'; |
| 173 |
|
| 174 |
if ( ! file_exists( $asset_file ) ) { |
| 175 |
return; |
| 176 |
} |
| 177 |
|
| 178 |
$assets = require $asset_file; |
| 179 |
$extra_dependencies = [ 'updates' ]; |
| 180 |
|
| 181 |
// Enqueue WordPress media uploader. |
| 182 |
wp_enqueue_media(); |
| 183 |
|
| 184 |
// Enqueue CodeMirror for CSS editor. |
| 185 |
wp_enqueue_code_editor( [ 'type' => 'text/css' ] ); |
| 186 |
|
| 187 |
wp_enqueue_script( |
| 188 |
'surecookie-admin', |
| 189 |
SURECOOKIE_URL . 'build/admin.js', |
| 190 |
array_merge( $assets['dependencies'] ?? [], $extra_dependencies ), |
| 191 |
$assets['version'] ?? SURECOOKIE_VERSION, |
| 192 |
true |
| 193 |
); |
| 194 |
wp_set_script_translations( 'surecookie-admin', 'surecookie', SURECOOKIE_DIR . 'languages' ); |
| 195 |
|
| 196 |
wp_enqueue_style( |
| 197 |
'surecookie-admin', |
| 198 |
SURECOOKIE_URL . 'build/' . Get::admin_style_css(), |
| 199 |
[], |
| 200 |
SURECOOKIE_VERSION |
| 201 |
); |
| 202 |
|
| 203 |
wp_enqueue_style( |
| 204 |
'surecookie-jodit-library', |
| 205 |
SURECOOKIE_URL . 'assets/css/' . Get::jodit_style_css(), |
| 206 |
[], |
| 207 |
SURECOOKIE_VERSION . '-jodit-4.12.18' |
| 208 |
); |
| 209 |
|
| 210 |
wp_enqueue_style( |
| 211 |
'surecookie-admin-styles', |
| 212 |
SURECOOKIE_URL . 'assets/css/' . Get::shared_style_css(), |
| 213 |
[ 'surecookie-admin' ], |
| 214 |
SURECOOKIE_VERSION |
| 215 |
); |
| 216 |
|
| 217 |
// Add palette CSS variables from stored option. |
| 218 |
$palette_css = Sanitize::stylesheet( Get::palette_root_css() ); |
| 219 |
if ( ! empty( $palette_css ) ) { |
| 220 |
wp_add_inline_style( 'surecookie-admin', wp_strip_all_tags( $palette_css ) ); |
| 221 |
} |
| 222 |
|
| 223 |
do_action( 'surecookie_admin_enqueue_scripts_after', $hook ); |
| 224 |
|
| 225 |
// Localize admin data using utility. |
| 226 |
LocalizeData::localize_admin_script( 'surecookie-admin' ); |
| 227 |
} |
| 228 |
|
| 229 |
/** |
| 230 |
* Drop other plugins' unscoped stylesheets from SureCookie's own screens. |
| 231 |
* |
| 232 |
* MemberPress Courses enqueues simplegrid.css on EVERY admin page; its |
| 233 |
* generic selectors (`.grid`, `[class*='col-']`) restyle Tailwind's grid |
| 234 |
* and col-span utilities and mangle this app's layout (ticket 1507247). |
| 235 |
* `mpcs-admin-shared` lists simplegrid as a dependency, so it has to go |
| 236 |
* too or WordPress prints simplegrid right back. |
| 237 |
* |
| 238 |
* @since 1.4.0 |
| 239 |
* @param string $hook The current admin page. |
| 240 |
* @return void |
| 241 |
*/ |
| 242 |
public function dequeue_conflicting_styles( $hook ): void { |
| 243 |
if ( ! in_array( $hook, self::PLUGIN_SCREEN_HOOKS, true ) ) { |
| 244 |
return; |
| 245 |
} |
| 246 |
|
| 247 |
foreach ( [ 'mpcs-admin-shared', 'mpcs-simplegrid', 'mepr-simplegrid' ] as $handle ) { |
| 248 |
wp_dequeue_style( $handle ); |
| 249 |
} |
| 250 |
} |
| 251 |
|
| 252 |
/** |
| 253 |
* Print styles and a click handler that open the Upgrade submenu in a new tab. |
| 254 |
* |
| 255 |
* Runs on every admin page because the submenu appears in the sidebar site-wide. |
| 256 |
* The CSS/JS selectors are scoped to `#toplevel_page_surecookie` so there is no |
| 257 |
* side effect on other admin screens. |
| 258 |
* |
| 259 |
* @since 1.0.0 |
| 260 |
* @return void |
| 261 |
*/ |
| 262 |
public function print_upgrade_submenu_assets(): void { |
| 263 |
?> |
| 264 |
<style> |
| 265 |
#adminmenu #toplevel_page_surecookie .wp-submenu a[href*="surecookie.com/pricing"] { |
| 266 |
background-color: #377A00 !important; |
| 267 |
color: #ffffff !important; |
| 268 |
font-weight: 500; |
| 269 |
font-size: 13px; |
| 270 |
line-height: 20px; |
| 271 |
padding-right: 12px !important; |
| 272 |
padding-left: 12px !important; |
| 273 |
} |
| 274 |
#adminmenu #toplevel_page_surecookie .wp-submenu a[href*="surecookie.com/pricing"]:hover, |
| 275 |
#adminmenu #toplevel_page_surecookie .wp-submenu a[href*="surecookie.com/pricing"]:focus { |
| 276 |
background-color: #2F6A00 !important; |
| 277 |
color: #ffffff !important; |
| 278 |
} |
| 279 |
</style> |
| 280 |
<script type="text/javascript"> |
| 281 |
document.addEventListener( 'DOMContentLoaded', function () { |
| 282 |
var link = document.querySelector( '#adminmenu #toplevel_page_surecookie .wp-submenu a[href*="surecookie.com/pricing"]' ); |
| 283 |
if ( ! link ) { |
| 284 |
return; |
| 285 |
} |
| 286 |
link.addEventListener( 'click', function ( e ) { |
| 287 |
e.preventDefault(); |
| 288 |
window.open( link.href, '_blank', 'noopener,noreferrer' ); |
| 289 |
} ); |
| 290 |
} ); |
| 291 |
</script> |
| 292 |
<?php |
| 293 |
} |
| 294 |
|
| 295 |
/** |
| 296 |
* Add action links to the plugin list page. |
| 297 |
* |
| 298 |
* @since 0.0.1 |
| 299 |
* @param array<string, string> $links Existing action links. |
| 300 |
* @return array<string, string> Modified action links. |
| 301 |
*/ |
| 302 |
public function plugin_action_links( $links ): array { |
| 303 |
$admin_url = admin_url( 'admin.php' ); |
| 304 |
|
| 305 |
$new_links = [ |
| 306 |
'settings' => sprintf( |
| 307 |
'<a href="%s">%s</a>', |
| 308 |
esc_url( add_query_arg( 'page', SURECOOKIE_PREFIX, $admin_url ) . '#/banner/content' ), |
| 309 |
esc_html__( 'Settings', 'surecookie' ) |
| 310 |
), |
| 311 |
]; |
| 312 |
|
| 313 |
return array_merge( $new_links, $links ); |
| 314 |
} |
| 315 |
|
| 316 |
/** |
| 317 |
* Register the "Upgrade" submenu under SureCookie. |
| 318 |
* |
| 319 |
* Uses a stable internal slug so that WordPress-generated hook names |
| 320 |
* (`load-{$slug}`, `admin_page_{$slug}`, etc.) stay clean. The external |
| 321 |
* pricing URL is then swapped into the `$submenu` global so WordPress |
| 322 |
* renders the item as an external link. The JS click handler printed in |
| 323 |
* `print_upgrade_submenu_assets()` intercepts the click and opens it in a |
| 324 |
* new tab, so the page is never actually navigated to - `'__return_null'` |
| 325 |
* is therefore a safe no-op callback. |
| 326 |
* |
| 327 |
* @since 1.0.0 |
| 328 |
* @return void |
| 329 |
*/ |
| 330 |
private function register_upgrade_submenu(): void { |
| 331 |
$upgrade_slug = SURECOOKIE_PREFIX . '_upgrade'; |
| 332 |
|
| 333 |
add_submenu_page( |
| 334 |
SURECOOKIE_PREFIX, |
| 335 |
__( 'Upgrade', 'surecookie' ), |
| 336 |
__( 'Upgrade', 'surecookie' ), |
| 337 |
SURECOOKIE_CAPABILITY, |
| 338 |
$upgrade_slug, |
| 339 |
'__return_null' |
| 340 |
); |
| 341 |
|
| 342 |
$upgrade_url = Helper::get_marketing_link( |
| 343 |
'pricing/', |
| 344 |
'pricing_submenu_link_upgrade' |
| 345 |
); |
| 346 |
|
| 347 |
// Swap the internal slug with the external pricing URL. Writing to the |
| 348 |
// $submenu global is the canonical WP pattern for linking a submenu item |
| 349 |
// to an external URL without polluting hook names with query strings. |
| 350 |
global $submenu; |
| 351 |
|
| 352 |
if ( ! isset( $submenu[ SURECOOKIE_PREFIX ] ) || ! is_array( $submenu[ SURECOOKIE_PREFIX ] ) ) { |
| 353 |
return; |
| 354 |
} |
| 355 |
|
| 356 |
foreach ( $submenu[ SURECOOKIE_PREFIX ] as $key => $item ) { |
| 357 |
if ( isset( $item[2] ) && $upgrade_slug === $item[2] ) { |
| 358 |
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Intentional: swap internal slug for external upgrade URL. |
| 359 |
$submenu[ SURECOOKIE_PREFIX ][ $key ][2] = $upgrade_url; |
| 360 |
break; |
| 361 |
} |
| 362 |
} |
| 363 |
} |
| 364 |
|
| 365 |
/** |
| 366 |
* Enqueue the inline style used for the top-level admin menu icon. |
| 367 |
* |
| 368 |
* @since 0.0.1 |
| 369 |
* @return void |
| 370 |
*/ |
| 371 |
private function enqueue_admin_menu_icon_style(): void { |
| 372 |
if ( ! is_admin() || ! current_user_can( SURECOOKIE_CAPABILITY ) ) { |
| 373 |
return; |
| 374 |
} |
| 375 |
|
| 376 |
if ( ! Settings::get( 'top_level_menu_enabled' ) ) { |
| 377 |
return; |
| 378 |
} |
| 379 |
|
| 380 |
wp_register_style( 'surecookie-admin-menu-icon', false, [], SURECOOKIE_VERSION ); |
| 381 |
wp_enqueue_style( 'surecookie-admin-menu-icon' ); |
| 382 |
wp_add_inline_style( 'surecookie-admin-menu-icon', $this->get_admin_menu_icon_css() ); |
| 383 |
wp_add_inline_style( 'surecookie-admin-menu-icon', $this->get_admin_menu_separator_css() ); |
| 384 |
wp_add_inline_style( 'surecookie-admin-menu-icon', $this->get_admin_menu_dot_css() ); |
| 385 |
} |
| 386 |
|
| 387 |
/** |
| 388 |
* Count the current user's unread consent logs. |
| 389 |
* |
| 390 |
* Centralizes the capability check and count lookup so the top-level menu |
| 391 |
* attention dot and the Logs submenu badge are driven by a single query. |
| 392 |
* |
| 393 |
* @since 1.2.3 |
| 394 |
* @return int |
| 395 |
*/ |
| 396 |
private function get_unread_logs_count(): int { |
| 397 |
if ( ! current_user_can( SURECOOKIE_CAPABILITY ) ) { |
| 398 |
return 0; |
| 399 |
} |
| 400 |
|
| 401 |
return ConsentLog::count_unread_logs_for_user( get_current_user_id() ); |
| 402 |
} |
| 403 |
|
| 404 |
/** |
| 405 |
* Build the top-level menu title, appending an attention dot for unread logs. |
| 406 |
* |
| 407 |
* The dot mirrors the pattern used across BSF plugins (e.g. SureForms) to |
| 408 |
* flag unseen activity on the parent menu item. It is removed client-side |
| 409 |
* once the Logs page is viewed (see AdminApp.jsx) and stops rendering on the |
| 410 |
* next load once the logs are marked as viewed server-side. |
| 411 |
* |
| 412 |
* @since 1.2.3 |
| 413 |
* @param int $unread_count Number of unread consent logs. |
| 414 |
* @return string |
| 415 |
*/ |
| 416 |
private function get_top_level_menu_title( int $unread_count ): string { |
| 417 |
$label = 'SureCookie'; |
| 418 |
|
| 419 |
if ( $unread_count <= 0 ) { |
| 420 |
return $label; |
| 421 |
} |
| 422 |
|
| 423 |
return $label . ' <span class="surecookie-update-dot" data-surecookie-logs-dot="true" aria-hidden="true"></span>'; |
| 424 |
} |
| 425 |
|
| 426 |
/** |
| 427 |
* Count the data requests still awaiting action. |
| 428 |
* |
| 429 |
* Free ships no data-request storage, so the number comes from Pro through |
| 430 |
* the filter; without Pro it stays 0 and the submenu shows the "New" badge. |
| 431 |
* |
| 432 |
* @since 1.4.0 |
| 433 |
* @return int |
| 434 |
*/ |
| 435 |
private function get_open_data_requests_count(): int { |
| 436 |
if ( ! current_user_can( SURECOOKIE_CAPABILITY ) ) { |
| 437 |
return 0; |
| 438 |
} |
| 439 |
|
| 440 |
return max( 0, (int) apply_filters( 'surecookie_open_data_requests_count', 0 ) ); |
| 441 |
} |
| 442 |
|
| 443 |
/** |
| 444 |
* Build the Data Requests submenu title. |
| 445 |
* |
| 446 |
* Mirrors the Consent Logs badge: an attention count when requests are |
| 447 |
* waiting, and a "New" pill in its place while there are none, so the |
| 448 |
* feature is still discoverable on a site that has never received one. |
| 449 |
* |
| 450 |
* @since 1.4.0 |
| 451 |
* @param int $open_count Number of data requests awaiting action. |
| 452 |
* @return string |
| 453 |
*/ |
| 454 |
private function get_data_requests_submenu_title( int $open_count ): string { |
| 455 |
$label = __( 'Data Requests', 'surecookie' ); |
| 456 |
|
| 457 |
if ( $open_count <= 0 ) { |
| 458 |
return sprintf( |
| 459 |
'%1$s <span class="surecookie-new-badge">%2$s</span>', |
| 460 |
$label, |
| 461 |
esc_html__( 'NEW', 'surecookie' ) |
| 462 |
); |
| 463 |
} |
| 464 |
|
| 465 |
return sprintf( |
| 466 |
'%1$s <span class="update-plugins count-%2$d" data-surecookie-data-requests-badge="true"><span class="plugin-count">%3$s</span></span>', |
| 467 |
$label, |
| 468 |
$open_count, |
| 469 |
esc_html( number_format_i18n( $open_count ) ) |
| 470 |
); |
| 471 |
} |
| 472 |
|
| 473 |
/** |
| 474 |
* Build the Logs submenu title with an unread-count badge when needed. |
| 475 |
* |
| 476 |
* @since 1.2.0 |
| 477 |
* @since 1.2.3 Accepts the pre-computed unread count instead of querying it. |
| 478 |
* @param int $unread_count Number of unread consent logs. |
| 479 |
* @return string |
| 480 |
*/ |
| 481 |
private function get_logs_submenu_title( int $unread_count ): string { |
| 482 |
$label = __( 'Consent Logs', 'surecookie' ); |
| 483 |
|
| 484 |
if ( $unread_count <= 0 ) { |
| 485 |
return $label; |
| 486 |
} |
| 487 |
|
| 488 |
return sprintf( |
| 489 |
'%1$s <span class="update-plugins count-%2$d" data-surecookie-logs-badge="true"><span class="plugin-count">%3$s</span></span>', |
| 490 |
$label, |
| 491 |
$unread_count, |
| 492 |
esc_html( number_format_i18n( $unread_count ) ) |
| 493 |
); |
| 494 |
} |
| 495 |
|
| 496 |
/** |
| 497 |
* Build the submenu group-separator stylesheet. |
| 498 |
* |
| 499 |
* @since 1.1.0 |
| 500 |
* @return string |
| 501 |
*/ |
| 502 |
private function get_admin_menu_separator_css(): string { |
| 503 |
return '#toplevel_page_surecookie li { |
| 504 |
clear: both; |
| 505 |
} |
| 506 |
#toplevel_page_surecookie li:not(:last-child) a[href^="admin.php?page=surecookie"]:after { |
| 507 |
border-bottom: 1px solid hsla(0,0%,100%,.2); |
| 508 |
display: block; |
| 509 |
float: left; |
| 510 |
margin: 13px -15px 8px; |
| 511 |
content: ""; |
| 512 |
width: calc(100% + 26px); |
| 513 |
} |
| 514 |
#toplevel_page_surecookie li:not(:last-child) a[href="admin.php?page=surecookie"]:after, |
| 515 |
#toplevel_page_surecookie li:not(:last-child) a[href^="admin.php?page=surecookie#/analytics"]:after, |
| 516 |
#toplevel_page_surecookie li:not(:last-child) a[href^="admin.php?page=surecookie#/learn"]:after, |
| 517 |
#toplevel_page_surecookie li:not(:last-child) a[href^="admin.php?page=surecookie#/banner/content"]:after { |
| 518 |
content: none; |
| 519 |
}'; |
| 520 |
} |
| 521 |
|
| 522 |
/** |
| 523 |
* Build the unread-logs attention dot stylesheet for the top-level menu. |
| 524 |
* |
| 525 |
* @since 1.2.3 |
| 526 |
* @return string |
| 527 |
*/ |
| 528 |
private function get_admin_menu_dot_css(): string { |
| 529 |
return '#toplevel_page_surecookie .wp-menu-name .surecookie-update-dot { |
| 530 |
display: inline-block; |
| 531 |
width: 8px; |
| 532 |
height: 8px; |
| 533 |
margin-left: 6px; |
| 534 |
border-radius: 50%; |
| 535 |
background: #d63638; |
| 536 |
vertical-align: middle; |
| 537 |
} |
| 538 |
#toplevel_page_surecookie .wp-submenu .surecookie-new-badge { |
| 539 |
background-color: #377a00; |
| 540 |
font-size: 9px; |
| 541 |
color: #fff; |
| 542 |
padding: 2px 4px; |
| 543 |
margin-left: 4px; |
| 544 |
border-radius: 4px; |
| 545 |
font-weight: 600; |
| 546 |
}'; |
| 547 |
} |
| 548 |
|
| 549 |
/** |
| 550 |
* Build the admin menu icon stylesheet. |
| 551 |
* |
| 552 |
* @since 0.0.1 |
| 553 |
* @return string |
| 554 |
*/ |
| 555 |
private function get_admin_menu_icon_css(): string { |
| 556 |
$icon_svg = 'data:image/svg+xml;base64,' . base64_encode( '<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256" fill="none"><path d="M97.0156 9.74499C120.404 0.0570803 146.141 -2.47884 170.971 2.45983C195.8 7.39873 218.609 19.59 236.51 37.4911L200.307 73.6942C189.566 62.9535 175.88 55.64 160.982 52.6766C146.085 49.7134 130.643 51.233 116.609 57.0458C102.576 62.8586 90.5814 72.7032 82.1426 85.3329C73.7038 97.9625 69.1992 112.811 69.1992 128.001C69.1992 140.594 72.2983 152.952 78.166 164.007C78.2596 164.006 78.3534 164.001 78.4473 164.001C89.4146 164.001 98.5033 172.026 100.17 182.524C105.185 179.335 111.141 177.497 117.525 177.518C133.572 177.572 146.835 189.36 149.221 204.729C153.155 204.564 157.087 204.1 160.982 203.325C175.88 200.362 189.566 193.046 200.307 182.306L236.51 218.511C218.609 236.412 195.8 248.603 170.971 253.542C146.141 258.48 120.404 255.945 97.0156 246.257C73.6273 236.569 53.6369 220.163 39.5723 199.114C25.5075 178.065 18 153.317 18 128.001C18 102.685 25.5074 77.9371 39.5723 56.8876C53.6369 35.8385 73.6272 19.433 97.0156 9.74499Z" fill="#A0A5AA"/><path d="M164 140.001C170.627 140.001 176 145.373 176 152.001C176 158.628 170.627 164.001 164 164.001C157.373 164.001 152 158.628 152 152.001C152 145.373 157.373 140.001 164 140.001Z" fill="#A0A5AA"/><path d="M108 108.001C114.627 108.001 120 113.373 120 120.001C120 126.628 114.627 132.001 108 132.001C101.373 132.001 96.0004 126.628 96 120.001C96 113.373 101.373 108.001 108 108.001Z" fill="#A0A5AA"/><path d="M152 76.0008C158.627 76.0008 164 81.3734 164 88.0008C164 94.6279 158.627 100.001 152 100.001C145.373 100.001 140 94.6279 140 88.0008C140 81.3734 145.373 76.0008 152 76.0008Z" fill="#A0A5AA"/></svg>' ); |
| 557 |
$active_icon_svg = 'data:image/svg+xml;base64,' . base64_encode( '<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256" fill="none"><path d="M97.0156 9.74499C120.404 0.0570803 146.141 -2.47884 170.971 2.45983C195.8 7.39873 218.609 19.59 236.51 37.4911L200.307 73.6942C189.566 62.9535 175.88 55.64 160.982 52.6766C146.085 49.7134 130.643 51.233 116.609 57.0458C102.576 62.8586 90.5814 72.7032 82.1426 85.3329C73.7038 97.9625 69.1992 112.811 69.1992 128.001C69.1992 140.594 72.2983 152.952 78.166 164.007C78.2596 164.006 78.3534 164.001 78.4473 164.001C89.4146 164.001 98.5033 172.026 100.17 182.524C105.185 179.335 111.141 177.497 117.525 177.518C133.572 177.572 146.835 189.36 149.221 204.729C153.155 204.564 157.087 204.1 160.982 203.325C175.88 200.362 189.566 193.046 200.307 182.306L236.51 218.511C218.609 236.412 195.8 248.603 170.971 253.542C146.141 258.48 120.404 255.945 97.0156 246.257C73.6273 236.569 53.6369 220.163 39.5723 199.114C25.5075 178.065 18 153.317 18 128.001C18 102.685 25.5074 77.9371 39.5723 56.8876C53.6369 35.8385 73.6272 19.433 97.0156 9.74499Z" fill="#FFFFFF"/><path d="M164 140.001C170.627 140.001 176 145.373 176 152.001C176 158.628 170.627 164.001 164 164.001C157.373 164.001 152 158.628 152 152.001C152 145.373 157.373 140.001 164 140.001Z" fill="#FFFFFF"/><path d="M108 108.001C114.627 108.001 120 113.373 120 120.001C120 126.628 114.627 132.001 108 132.001C101.373 132.001 96.0004 126.628 96 120.001C96 113.373 101.373 108.001 108 108.001Z" fill="#FFFFFF"/><path d="M152 76.0008C158.627 76.0008 164 81.3734 164 88.0008C164 94.6279 158.627 100.001 152 100.001C145.373 100.001 140 94.6279 140 88.0008C140 81.3734 145.373 76.0008 152 76.0008Z" fill="#FFFFFF"/></svg>' ); |
| 558 |
|
| 559 |
return implode( |
| 560 |
"\n", |
| 561 |
[ |
| 562 |
'#toplevel_page_surecookie .wp-menu-image:before {', |
| 563 |
"\tcontent: '';", |
| 564 |
"\tmask-image: url(" . wp_json_encode( $icon_svg ) . ');', |
| 565 |
"\tmask-size: contain;", |
| 566 |
"\tmask-repeat: no-repeat;", |
| 567 |
"\tmask-position: center;", |
| 568 |
"\tbackground-color: currentColor;", |
| 569 |
'}', |
| 570 |
'#toplevel_page_surecookie .wp-menu-image {', |
| 571 |
"\talign-content: center;", |
| 572 |
'}', |
| 573 |
'#toplevel_page_surecookie.current .wp-menu-image:before,', |
| 574 |
'#toplevel_page_surecookie.wp-has-current-submenu .wp-menu-image:before {', |
| 575 |
"\tmask-image: url(" . wp_json_encode( $active_icon_svg ) . ');', |
| 576 |
'}', |
| 577 |
] |
| 578 |
); |
| 579 |
} |
| 580 |
} |
| 581 |
|