label. */ public static function tabs() { return array( 'dashboard' => __( 'Dashboard', 'markitmall-dropship' ), 'catalog' => __( 'Catalog', 'markitmall-dropship' ), 'imports' => __( 'My imports', 'markitmall-dropship' ), 'orders' => __( 'Orders', 'markitmall-dropship' ), 'settings' => __( 'Settings', 'markitmall-dropship' ), ); } /** Link to a tab, with extra query args. */ public static function url( $tab = 'dashboard', $args = array() ) { return add_query_arg( array_merge( array( 'page' => self::PAGE, 'tab' => $tab ), $args ), admin_url( 'admin.php' ) ); } /** Redirect back to a tab with a notice code (see notices()). */ public static function redirect( $tab, $notice = '', $args = array() ) { if ( $notice ) { $args['mm_notice'] = $notice; } wp_safe_redirect( self::url( $tab, $args ) ); exit; } public static function menu() { add_menu_page( __( 'MarkitMall Dropship', 'markitmall-dropship' ), __( 'MarkitMall', 'markitmall-dropship' ), 'manage_woocommerce', self::PAGE, array( __CLASS__, 'render' ), MARKITMALL_DS_URL . 'assets/icon.png', 56 ); // Sub-items that open the tabs, so each is one click from the menu. A // sub-item without a page of its own links to its slug as given, so the // slug is the tab's full admin URL. foreach ( self::tabs() as $tab => $label ) { add_submenu_page( self::PAGE, $label, $label, 'manage_woocommerce', self::submenu_slug( $tab ), 'dashboard' === $tab ? array( __CLASS__, 'render' ) : '' ); } } private static function submenu_slug( $tab ) { return 'dashboard' === $tab ? self::PAGE : 'admin.php?page=' . self::PAGE . '&tab=' . $tab; } /** Version 1.0 had the catalog on its own page; send its bookmarks to the tab. */ public static function old_catalog_url() { if ( isset( $_GET['page'] ) && 'markitmall-dropship-catalog' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification wp_safe_redirect( self::url( 'catalog' ) ); exit; } } public static function current_tab() { $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'dashboard'; // phpcs:ignore WordPress.Security.NonceVerification return isset( self::tabs()[ $tab ] ) ? $tab : 'dashboard'; } /** * The admin screens a MarkitMall notice may appear on (Guideline 11: no * notices across the whole dashboard): this plugin's screen, plus the * WooCommerce screens the notice is about — "orders" or "products". */ public static function is_notice_screen( $about ) { if ( self::is_our_page() ) { return true; } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen ) { return false; } $ids = 'orders' === $about ? array( 'edit-shop_order', 'shop_order', 'woocommerce_page_wc-orders' ) : array( 'edit-product' ); return in_array( $screen->id, $ids, true ); } public static function is_our_page() { return isset( $_GET['page'] ) && self::PAGE === $_GET['page']; // phpcs:ignore WordPress.Security.NonceVerification } public static function assets() { // The menu icon is a photo-like PNG: size it like WordPress's own icons, on every admin page. wp_add_inline_style( 'admin-menu', '#adminmenu .toplevel_page_markitmall-dropship .wp-menu-image img{width:20px;height:20px;padding:7px 0 0;opacity:1}' ); if ( ! self::is_our_page() ) { return; } wp_enqueue_style( 'markitmall-dropship-admin', MARKITMALL_DS_URL . 'assets/admin.css', array(), MARKITMALL_DS_VERSION ); } /** Highlights the menu sub-item of the open tab. */ public static function submenu_highlight( $submenu_file ) { if ( ! self::is_our_page() ) { return $submenu_file; } return self::submenu_slug( self::current_tab() ); } public static function render() { if ( ! current_user_can( 'manage_woocommerce' ) ) { return; } $tab = self::current_tab(); $connected = MarkitMall_DS_API::is_configured(); $settings = MarkitMall_DS_Settings::get_all(); ?>

array( 'success', __( 'Settings saved.', 'markitmall-dropship' ) ), 'connected' => array( 'success', __( 'Connected. MarkitMall will send order updates to this site.', 'markitmall-dropship' ) ), 'connected_local' => array( 'warning', __( 'Connected. MarkitMall cannot reach this site to send order updates (', 'markitmall-dropship' ) . $error . __( '). Everything else works; on a public site, press “Re-register webhook” under Settings → Advanced.', 'markitmall-dropship' ) ), 'webhook_ok' => array( 'success', __( 'Webhook registered.', 'markitmall-dropship' ) ), 'webhook_failed' => array( 'error', __( 'The webhook could not be registered: ', 'markitmall-dropship' ) . $error ), 'test_ok' => array( 'success', __( 'Connection works.', 'markitmall-dropship' ) ), 'test_failed' => array( 'error', __( 'Could not connect: ', 'markitmall-dropship' ) . $error ), 'bad_key' => array( 'error', __( 'Paste the whole key exactly as your MarkitMall dashboard shows it: Bearer mk_…:sk_…', 'markitmall-dropship' ) ), 'wrong_integration' => array( 'error', __( 'This key belongs to another kind of store connection. In your MarkitMall dashboard → Integrations, connect a WooCommerce store and create a key for it.', 'markitmall-dropship' ) ), 'disconnected' => array( 'success', __( 'Disconnected from MarkitMall. Your imported products stay in your store.', 'markitmall-dropship' ) ), 'retried' => array( 'info', __( 'Sent — the order’s notes show the result.', 'markitmall-dropship' ) ), 'delivery_ok' => array( 'success', __( 'Delivery rates set up: MarkitMall delivery is on in your Pakistan shipping zone.', 'markitmall-dropship' ) ), 'delivery_already' => array( 'info', __( 'Delivery rates are already set up.', 'markitmall-dropship' ) ), 'delivery_failed' => array( 'error', __( 'Delivery rates could not be set up: ', 'markitmall-dropship' ) . $error ), 'imported' => array( 'success', __( 'Imported — it is in your Products. Stock and price updates arrive automatically.', 'markitmall-dropship' ) ), 'relinked' => array( 'success', __( 'Re-linked with MarkitMall.', 'markitmall-dropship' ) ), 'removed' => array( 'success', __( 'Removed from your store. You can import it again any time.', 'markitmall-dropship' ) ), 'import_failed' => array( 'error', $error ), ); if ( ! isset( $messages[ $code ] ) ) { return; } echo '

' . esc_html( $messages[ $code ][1] ) . '

'; } // ── Small building blocks shared by the tabs ────────────────────────────── public static function stat( $label, $value, $hint = '' ) { echo '

' . esc_html( $label ) . '

' . esc_html( $value ) . '

'; if ( $hint ) { echo '

' . esc_html( $hint ) . '

'; } echo '
'; } /** A coloured status label: tone is good, warn, bad, brand or plain. */ public static function badge( $label, $tone = 'plain' ) { return '' . esc_html( $label ) . ''; } public static function rs( $amount ) { return 'Rs ' . number_format_i18n( (float) $amount ); } /** Disables a form's button while it submits, so one click cannot send it twice. */ public static function busy_js( $label ) { return "var b=this.querySelector('button[type=submit],button:not([type])');if(b){if(b.disabled){return false;}b.disabled=true;b.textContent='" . esc_js( $label ) . "';}"; } /** An admin-post.php form button: action, nonce, hidden fields, one button. */ public static function action_button( $action, $label, $fields = array(), $class = 'mm-btn', $confirm = '', $busy = '' ) { $onsubmit = ''; if ( $confirm ) { $onsubmit .= "if(!confirm('" . esc_js( $confirm ) . "')){return false;}"; } if ( $busy ) { $onsubmit .= self::busy_js( $busy ); } echo '
'; echo ''; wp_nonce_field( $action ); foreach ( $fields as $name => $value ) { echo ''; } echo '
'; } }