" (its title, PrintBlob, is not translated). */ public const SCREEN = 'toplevel_page_printblob'; public const SCREEN_PREFIX = 'printblob_page_'; public static function register(): void { add_action( 'admin_menu', array( __CLASS__, 'add' ) ); add_filter( 'menu_order', array( __CLASS__, 'after_products' ), 11 ); add_filter( 'admin_footer_text', array( __CLASS__, 'footer_text' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue' ) ); add_filter( 'site_status_test_result', array( Overview::class, 'keep_print_folder' ) ); } public static function url(): string { return admin_url( 'admin.php?page=' . self::SLUG ); } public static function add(): void { $overview = __( 'PrintBlob overview', 'printblob' ); add_menu_page( $overview, 'PrintBlob', self::CAPABILITY, self::SLUG, array( Overview::class, 'render' ), FACTS['menu_icon'], '55.7' ); add_submenu_page( self::SLUG, $overview, __( 'Overview', 'printblob' ), self::CAPABILITY, self::SLUG, array( Overview::class, 'render' ) ); add_submenu_page( self::SLUG, __( 'PrintBlob settings', 'printblob' ), __( 'Settings', 'printblob' ), self::CAPABILITY, 'admin.php?page=wc-settings&tab=printblob' ); /** * Fires after PrintBlob's menu, its Overview and Settings are added, for other code's items under it. * * @param string $parent_slug The menu's slug, the parent of its items. */ do_action( 'printblob_admin_menu', self::SLUG ); if ( ! Settings::pro_active() ) { add_submenu_page( self::SLUG, __( 'Print queue', 'printblob' ), __( 'Print queue', 'printblob' ), self::CAPABILITY, Print_Queue::PAGE, array( Print_Queue::class, 'render' ) ); } add_submenu_page( self::SLUG, __( 'PrintBlob Pro', 'printblob' ), __( 'PrintBlob Pro', 'printblob' ), self::CAPABILITY, Pro::PAGE, array( Pro::class, 'compare_page' ) ); if ( ! Settings::pro_active() && current_user_can( self::CAPABILITY ) ) { global $submenu; // add_submenu_page() runs a slug through plugin_basename(), which turns the "//" of an address into "/"; WordPress 7.1 prints an item's slug as its link unescaped. $submenu[ self::SLUG ][] = array( '' . esc_html__( 'Get Pro', 'printblob' ) . '', self::CAPABILITY, esc_url( Pro::checkout_url( 'menu' ) ), __( 'Get PrintBlob Pro', 'printblob' ), 'printblob-get-pro' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- The documented way to add a menu item that leaves the admin. } add_submenu_page( 'woocommerce', $overview, 'PrintBlob', self::CAPABILITY, 'admin.php?page=' . self::SLUG ); } /** * WooCommerce orders its menu as WooCommerce, then Products; PrintBlob follows Products. * * @param string[] $order Menu slugs in order. */ public static function after_products( $order ) { if ( ! is_array( $order ) ) { return $order; } $order = array_values( array_diff( $order, array( self::SLUG ) ) ); // WooCommerce's own ordering moves Products after WooCommerce and leaves its first place in the list too: the // place WordPress keeps is the last one. $products = array_keys( $order, 'edit.php?post_type=product', true ); if ( array() === $products ) { return $order; } array_splice( $order, (int) end( $products ) + 1, 0, array( self::SLUG ) ); return $order; } /** * On PrintBlob's own screens, one line in the admin footer asking for a review on WordPress.org. * * @param string $text The footer's text. */ public static function footer_text( $text ) { if ( 'own' !== self::surface() || ! current_user_can( self::CAPABILITY ) ) { return $text; } return self::footer_html(); } public static function footer_html(): string { return sprintf( /* translators: %s: five stars, linking to PrintBlob's reviews on WordPress.org. */ esc_html__( 'If PrintBlob helps your shop, please rate it %s on WordPress.org.', 'printblob' ), '★★★★★' ); } /** * Refuses an admin-post request without the nonce of `$action` (action_url() makes it) or from a user without * `$capability`. */ public static function guard( string $action, string $capability = self::CAPABILITY ): void { check_admin_referer( $action ); self::allow( $capability ); } /** Refuses a user without `$capability`. */ public static function allow( string $capability = self::CAPABILITY ): void { if ( ! current_user_can( $capability ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'printblob' ), 403 ); } } /** Ends the request with a redirect back to the screen it came from, or to `$fallback` (the dashboard when empty). */ public static function back( string $fallback = '' ): void { $back = wp_get_referer(); wp_safe_redirect( $back ? $back : ( '' !== $fallback ? $fallback : admin_url() ) ); exit; } /** * The address of one of PrintBlob's admin-post actions, with a nonce named after it (raw: escape it where printed). * * @param string $action The action. * @param array $args More query arguments. */ public static function action_url( string $action, array $args = array() ): string { return wp_nonce_url( add_query_arg( array( 'action' => $action ) + $args, admin_url( 'admin-post.php' ) ), $action ); } /** * A ✓ or ✗, or a neutral – for neither, with what it means in words, beside it or only for screen readers. * * @param bool|null $yes Which mark; null for neither. * @param string $words What it means. * @param bool $shown Whether the words are shown beside it. */ public static function mark_html( ?bool $yes, string $words, bool $shown = true ): string { return sprintf( '%3$s', null === $yes ? 'none' : ( $yes ? 'yes' : 'no' ), null === $yes ? '–' : ( $yes ? '✓' : '✗' ), $shown ? ' ' . esc_html( $words ) . '' : '' . esc_html( $words ) . '' ); } /** * Which of PrintBlob's admin surfaces the screen shown is: `own` (its own screens), `product` or `order` (the edit * screens its controls are on), `plugins`, or '' for any other. Worked out once a request, by the first hook that * asks after WordPress has set the screen. */ public static function surface(): string { static $surface = null; if ( null !== $surface ) { return $surface; } $screen = get_current_screen(); if ( ! $screen ) { return ''; } if ( Settings::on_own_screen() ) { $surface = 'own'; } elseif ( 'post' === $screen->base && 'product' === $screen->post_type ) { $surface = 'product'; } elseif ( Order::on_edit_screen() ) { $surface = 'order'; } else { $surface = 'plugins' === $screen->id ? 'plugins' : ''; } return $surface; } /** Whether the admin screen shown has PrintBlob on it: its own screens, and the product and order screens. */ public static function on_printblob_surface(): bool { return in_array( self::surface(), array( 'own', 'product', 'order' ), true ); } /** PrintBlob's admin styles: its own screens, and the product and order screens, where its Pro controls are. */ public static function enqueue(): void { if ( ! self::on_printblob_surface() ) { return; } wp_enqueue_style( 'printblob-admin', plugins_url( 'assets/admin/admin.css', FILE ), array( 'dashicons' ), VERSION ); } }