get_base64_admin_menu_logo() : $logo->get_base64_logo(); return add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_admin_page', 'jetpack', array( $this, 'render' ), $icon, 3 ); } /** * Add page action. * * @param string $hook Hook of current page. * @return void */ public function add_page_actions( $hook ) { /** This action is documented in class.jetpack-admin.php */ do_action( 'jetpack_admin_menu', $hook ); if ( ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } $page = sanitize_text_field( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( 'jetpack' !== $page ) { if ( strpos( $page, 'jetpack/' ) === 0 ) { $section = substr( $page, 8 ); wp_safe_redirect( admin_url( 'admin.php?page=jetpack#/' . $section ) ); exit( 0 ); } return; // No need to handle the fallback redirection if we are not on the Jetpack page. } // After the action handlers and the connection controller, which exit when they act. add_action( "load-$hook", array( $this, 'render_redirect_document' ), PHP_INT_MAX ); // If this is the first time the user is viewing the admin, don't show JITMs. // This filter is added just in time because this function is called on admin_menu // and JITMs are initialized on admin_init. if ( Jetpack::is_connection_ready() && ! Jetpack_Options::get_option( 'first_admin_view', false ) ) { Jetpack_Options::update_option( 'first_admin_view', true ); add_filter( 'jetpack_just_in_time_msgs', '__return_false' ); } } /** * Remove the main Jetpack submenu if a site is in offline mode or connected * or if My Jetpack is available. * At that point, admins can access the Jetpack Dashboard instead. * * @since 13.8 */ public function remove_jetpack_menu() { $is_offline_mode = ( new Status() )->is_offline_mode(); $has_my_jetpack = ( class_exists( 'Automattic\Jetpack\My_Jetpack\Initializer' ) && method_exists( 'Automattic\Jetpack\My_Jetpack\Initializer', 'should_initialize' ) && \Automattic\Jetpack\My_Jetpack\Initializer::should_initialize() ); if ( $is_offline_mode || $has_my_jetpack || Jetpack::is_connection_ready() ) { remove_submenu_page( 'jetpack', 'jetpack' ); } } /** * Where links into page=jetpack land. * * Settings hashes keep their hash on the Settings page. Admins go to My Jetpack * wherever it runs; everyone else, and a request with a pending error, lands on * Settings. While the partner coupon screen applies, every route goes there. * * @return array{settings: string, forward: string[], routes: array, fallback: string} */ public static function get_legacy_route_redirects() { $settings_url = admin_url( 'admin.php?page=jetpack-settings' ); $coupon_screen = self::get_partner_coupon_redirect(); if ( $coupon_screen ) { return array( 'settings' => $settings_url, 'forward' => array(), 'routes' => array(), 'fallback' => $coupon_screen, ); } $table = array( 'settings' => $settings_url, 'forward' => self::SETTINGS_ROUTES, 'routes' => array(), 'fallback' => $settings_url, ); if ( ! self::should_redirect_legacy_routes() ) { return $table; } $pricing_url = Redirect::get_url( 'jetpack-plans' ); $table['routes'] = array( '/plans' => $pricing_url, '/plans-prompt' => $pricing_url, '/newsletter' => admin_url( 'admin.php?page=jetpack-newsletter' ), ); if ( self::can_use_my_jetpack() ) { $my_jetpack = admin_url( 'admin.php?page=my-jetpack' ); foreach ( array( 'akismet', 'backup', 'scan', 'search', 'security', 'videopress' ) as $product ) { $table['routes'][ '/product/' . $product ] = $my_jetpack . '#/add-' . $product; } $table['routes']['/license/activation'] = $my_jetpack . '#/add-license'; foreach ( array( '/reconnect', '/disconnect', '/woo-setup' ) as $route ) { $table['routes'][ $route ] = $my_jetpack . '#/connection'; } $table['fallback'] = $my_jetpack; } return $table; } /** * Whether this request may leave Settings. * * @return bool */ public static function should_redirect_legacy_routes() { // A pending error only renders via the Settings app's state notices. return ! Jetpack::state( 'error' ); } /** * Print the legacy route redirect; it runs in the browser because the server never sees the hash. */ public function print_legacy_route_redirect() { $table = self::get_legacy_route_redirects(); $flags = JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP; wp_print_inline_script_tag( sprintf( '( %s )( %s, %s, %s, %s );', self::LEGACY_ROUTE_REDIRECT_SCRIPT, wp_json_encode( $table['settings'], $flags ), wp_json_encode( $table['forward'], $flags ), wp_json_encode( (object) $table['routes'], $flags ), wp_json_encode( $table['fallback'], $flags ) ) ); } /** * Replace page=jetpack with the redirect document; nothing else renders here. * * @since 16.3 * * @return never */ public function render_redirect_document() { $table = self::get_legacy_route_redirects(); if ( $table['settings'] === $table['fallback'] ) { // Settings renders this request's notices, so its state must survive the hop. Jetpack::restate(); } $this->print_redirect_document(); exit( 0 ); } /** * Print a bare document that only redirects. * * @since 16.3 */ public function print_redirect_document() { ?> > Jetpack is_rest_api_enabled() ) { $this->print_legacy_route_redirect(); $this->add_noscript_head_meta(); } else { $this->add_fallback_head_meta(); } ?> admin_url( 'admin.php?page=jetpack' ), ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $target = sanitize_text_field( wp_unslash( $_GET['jp-react-redirect'] ) ); if ( isset( $allowed_paths[ $target ] ) ) { wp_safe_redirect( $allowed_paths[ $target ] ); exit( 0 ); } } /** * Nothing loads here: render_redirect_document() exits on load. */ public function page_admin_scripts() {} }