settings = $settings; } public function register() { add_action( 'admin_menu', array( $this, 'menu' ), 99 ); add_action( 'admin_enqueue_scripts', array( $this, 'assets' ) ); add_action( 'in_admin_header', array( $this, 'strip_preview_chrome' ), 0 ); add_filter( 'admin_body_class', array( $this, 'body_class' ) ); add_filter( 'parent_file', array( $this, 'highlight_artbees_menu' ) ); add_filter( 'submenu_file', array( $this, 'highlight_quick_view_submenu' ) ); } public function menu() { if ( ! $this->artbees_parent_exists() ) { add_menu_page( __( 'Artbees', 'artbees-quick-view' ), __( 'Artbees', 'artbees-quick-view' ), 'manage_woocommerce', self::ARTBEES_MENU_SLUG, array( $this, 'redirect_to_workspace' ), $this->admin_menu_icon(), 56 ); } add_submenu_page( self::ARTBEES_MENU_SLUG, __( 'Artbees Quick View', 'artbees-quick-view' ), __( 'Quick View', 'artbees-quick-view' ), 'manage_woocommerce', 'artbees-quick-view', array( $this, 'setup_screen' ) ); remove_submenu_page( self::ARTBEES_MENU_SLUG, self::ARTBEES_MENU_SLUG ); // A null parent makes admin-header.php pass null into strip_tags(). These // screens stay URL-reachable and keep the admin_page_{slug} hook Pro matches. // WordPress recalculates the parent after parent_file filters, so the hidden // parent is mapped back to Artbees and Quick View stays highlighted. $this->hidden_screen( __( 'Quick View Settings', 'artbees-quick-view' ), __( 'Settings', 'artbees-quick-view' ), 'artbees-quick-view-settings', array( $this, 'settings_screen' ) ); $this->hidden_screen( __( 'Quick View Visibility', 'artbees-quick-view' ), __( 'Visibility', 'artbees-quick-view' ), 'artbees-quick-view-visibility', array( $this, 'visibility_screen' ) ); $this->hidden_screen( __( 'Quick View Status', 'artbees-quick-view' ), __( 'Status', 'artbees-quick-view' ), 'artbees-quick-view-status', array( $this, 'status_screen' ) ); if ( defined( 'artbees_QV_PRO_VERSION' ) ) { $this->hidden_screen( __( 'Quick View Advanced', 'artbees-quick-view' ), __( 'Advanced', 'artbees-quick-view' ), 'artbees-quick-view-advanced', array( $this, 'advanced_screen' ) ); } $this->hidden_screen( __( 'Quick View preview', 'artbees-quick-view' ), __( 'Quick View preview', 'artbees-quick-view' ), 'artbees-quick-view-preview', array( $this, 'preview_screen' ) ); global $_wp_real_parent_file; if ( ! is_array( $_wp_real_parent_file ) ) { $_wp_real_parent_file = array(); } $_wp_real_parent_file[ self::HIDDEN_PARENT ] = self::ARTBEES_MENU_SLUG; } private function hidden_screen( $page_title, $menu_title, $slug, $callback ) { global $_registered_pages; add_submenu_page( self::HIDDEN_PARENT, $page_title, $menu_title, 'manage_woocommerce', $slug, $callback ); // Authorization resolves the highlighted Artbees parent and checks that hook. if ( ! is_array( $_registered_pages ) ) { $_registered_pages = array(); } $_registered_pages[ get_plugin_page_hookname( $slug, self::ARTBEES_MENU_SLUG ) ] = true; } public function redirect_to_workspace() { wp_safe_redirect( admin_url( 'admin.php?page=artbees-quick-view' ) ); exit; } private function artbees_parent_exists() { global $menu; foreach ( is_array( $menu ) ? $menu : array() as $menu_item ) { if ( is_array( $menu_item ) && isset( $menu_item[2] ) && self::ARTBEES_MENU_SLUG === $menu_item[2] ) { return true; } } return false; } private function admin_menu_icon() { $path = __DIR__ . '/assets/artbees-admin-menu-icon.svg'; if ( ! is_readable( $path ) ) { return 'dashicons-art'; } $svg = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents return is_string( $svg ) && '' !== $svg ? 'data:image/svg+xml;base64,' . base64_encode( $svg ) : 'dashicons-art'; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode } public function highlight_artbees_menu( $parent_file ) { return $this->is_workspace_page() && $this->artbees_parent_exists() ? self::ARTBEES_MENU_SLUG : $parent_file; } public function highlight_quick_view_submenu( $submenu_file ) { return $this->is_workspace_page() ? 'artbees-quick-view' : $submenu_file; } private function is_workspace_page() { $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page identifier. return 'artbees-quick-view' === $page || 0 === strpos( $page, 'artbees-quick-view-' ); } public function setup_screen() { $this->screen( 'setup' ); } public function settings_screen() { $this->screen( 'settings' ); } public function visibility_screen() { $this->screen( 'visibility' ); } public function status_screen() { $this->screen( 'status' ); } public function advanced_screen() { $this->screen( 'advanced' ); } public function preview_screen() { $this->screen( 'preview' ); } public function is_preview_page() { return isset( $_GET['page'] ) && 'artbees-quick-view-preview' === $_GET['page']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page flag. } public function strip_preview_chrome() { if ( ! $this->is_preview_page() ) { return; } remove_all_actions( 'admin_notices' ); remove_all_actions( 'all_admin_notices' ); remove_all_actions( 'user_admin_notices' ); remove_all_actions( 'network_admin_notices' ); } public function body_class( $classes ) { if ( $this->is_preview_page() ) { $classes .= ' artbees-qv-preview-page'; } return $classes; } private function screen( $tab ) { if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You do not have permission to manage Artbees Quick View for WooCommerce.', 'artbees-quick-view' ) ); } if ( 'advanced' === $tab && defined( 'artbees_QV_PRO_VERSION' ) ) { echo '

' . esc_html__( 'Loading Quick View…', 'artbees-quick-view' ) . '

'; return; } if ( 'preview' === $tab ) { echo '

' . esc_html__( 'Loading Artbees Quick View for WooCommerce preview…', 'artbees-quick-view' ) . '

'; return; } echo '

' . esc_html__( 'Loading Artbees Quick View for WooCommerce settings…', 'artbees-quick-view' ) . '

'; } public function assets( $hook ) { $tabs = array( 'artbees-quick-view' => 'setup', 'artbees-quick-view-settings' => 'settings', 'artbees-quick-view-visibility' => 'visibility', 'artbees-quick-view-status' => 'status', 'artbees-quick-view-advanced' => 'advanced', 'artbees-quick-view-preview' => 'preview', ); $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page identifier. if ( ! isset( $tabs[ $page ] ) ) { return; } if ( 'advanced' === $tabs[ $page ] && defined( 'artbees_QV_PRO_VERSION' ) ) { return; } $asset = artbees_QV_PATH . 'build/admin/index.asset.php'; $dependencies = array( 'wp-components', 'wp-element', 'wp-i18n', 'wp-api-fetch' ); $version = artbees_QV_VERSION; if ( file_exists( $asset ) ) { $metadata = require $asset; $dependencies = $metadata['dependencies']; $version = $metadata['version']; } wp_enqueue_script( 'artbees-qv-admin', artbees_QV_URL . 'build/admin/index.js', $dependencies, $version, true ); $style = artbees_QV_PATH . 'build/admin/style-index.css'; if ( file_exists( $style ) ) { wp_enqueue_style( 'artbees-qv-admin', artbees_QV_URL . 'build/admin/style-index.css', array( 'wp-components' ), $version ); } wp_set_script_translations( 'artbees-qv-admin', 'artbees-quick-view' ); wp_add_inline_script( 'artbees-qv-admin', 'window.artbeesQvAdmin = ' . wp_json_encode( array( 'settings' => $this->settings->get(), 'proActive' => defined( 'artbees_QV_PRO_VERSION' ), 'version' => (int) get_option( \artbees\QuickView\Storage\SettingsRepository::VERSION_OPTION, 0 ), 'visibility' => ( new VisibilityBootData( $this->settings ) )->get(), 'restUrl' => esc_url_raw( rest_url( 'artbees-quick-view/v1/' ) ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'tab' => $tabs[ $page ], 'previewUrl' => esc_url_raw( admin_url( 'admin.php?page=artbees-quick-view-preview' ) ), ) ) . ';', 'before' ); } }