sessions = $sessions; } /** * Hooks. */ public function register_hooks(): void { add_action( 'admin_notices', array( $this, 'render' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) ); add_action( 'admin_post_bloatwright_dismiss_notice', array( $this, 'dismiss' ) ); } /** * Whether the first-run nudge shows: only on the Plugins screen, only to users who can run profiles, * only until the first session exists, and never again after it is dismissed. * * @return bool */ private function show_first_run(): bool { if ( ! current_user_can( Settings::capability() ) || '' !== Menu::current_page() ) { return false; } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || 'plugins' !== $screen->id ) { return false; } $dismissed = (array) get_user_meta( get_current_user_id(), 'bloatwright_dismissed_notices', true ); return ! in_array( 'first_run', $dismissed, true ) && ! $this->sessions->all( 1 ); } /** * Dismiss URL for the first-run nudge. * * @return string */ private function dismiss_url(): string { return wp_nonce_url( admin_url( 'admin-post.php?action=bloatwright_dismiss_notice&bloatwright_notice=first_run' ), 'bloatwright_dismiss_first_run' ); } /** * Makes the first-run nudge's close (×) button remember the dismissal, like the Dismiss link does. * * @param string $hook Admin page hook. */ public function enqueue( $hook ): void { if ( 'plugins.php' !== $hook || ! $this->show_first_run() ) { return; } wp_register_script( 'bloatwright-notice', false, array(), BLOATWRIGHT_VERSION, true ); wp_enqueue_script( 'bloatwright-notice' ); wp_add_inline_script( 'bloatwright-notice', "document.addEventListener('click',function(e){var b=e.target&&e.target.closest?e.target.closest('.bloatwright-notice .notice-dismiss'):null;if(!b||!window.fetch){return;}var n=b.closest('.bloatwright-notice');var u=n?n.getAttribute('data-dismiss-url'):'';if(u){window.fetch(u,{credentials:'same-origin',redirect:'manual'});}});" ); } /** * Render. */ public function render(): void { if ( ! current_user_can( Settings::capability() ) ) { return; } if ( '' !== Menu::current_page() && ! LoaderInstaller::installed() && ! LoaderInstaller::writable() ) { printf( '

%s %s %s

', esc_html__( 'Bloatwright cannot write its loader.', 'bloatwright' ), esc_html__( 'The first profiling run writes one small must-use plugin. Make this directory writable:', 'bloatwright' ), esc_html( dirname( LoaderInstaller::target() ) ) ); } if ( $this->show_first_run() ) { $pages = count( UrlSet::defaults() ); printf( '

%s %s %s %s

', esc_url( $this->dismiss_url() ), esc_html__( 'Bloatwright is ready.', 'bloatwright' ), /* translators: %d: number of pages in the default URL set */ esc_html( sprintf( _n( 'Measure how much each plugin costs on %d typical page of this site. Visitors are not affected.', 'Measure how much each plugin costs on %d typical pages of this site. Visitors are not affected.', $pages, 'bloatwright' ), $pages ) ), esc_url( admin_url( 'tools.php?page=' . Menu::SLUG ) ), esc_html__( 'Run a profile', 'bloatwright' ), esc_url( $this->dismiss_url() ), esc_html__( 'Dismiss', 'bloatwright' ) ); } } /** * Notice ids that can be dismissed. */ const NOTICES = array( 'first_run' ); /** * Dismiss. */ public function dismiss(): void { $notice = isset( $_GET['bloatwright_notice'] ) ? sanitize_key( wp_unslash( $_GET['bloatwright_notice'] ) ) : ''; check_admin_referer( 'bloatwright_dismiss_' . $notice ); if ( ! current_user_can( Settings::capability() ) ) { wp_die( esc_html__( 'You are not allowed to do that.', 'bloatwright' ), '', array( 'response' => 403 ) ); } if ( ! in_array( $notice, self::NOTICES, true ) ) { wp_die( esc_html__( 'Unknown notice.', 'bloatwright' ), '', array( 'response' => 400 ) ); } $dismissed = (array) get_user_meta( get_current_user_id(), 'bloatwright_dismissed_notices', true ); $dismissed[] = $notice; update_user_meta( get_current_user_id(), 'bloatwright_dismissed_notices', array_values( array_unique( array_filter( $dismissed ) ) ) ); wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url() ); exit; } }