array( 'Sales', 'Orders, preparation, shipping and payment status.', 'cart', 'storesuit-orders', 'Sales management' ), 'products' => array( 'Products', 'Products, options, prices and stock.', 'products', 'storesuit-products', 'Product management' ), 'customers' => array( 'Customers', 'Customer history, contact details, and individual orders.', 'groups', 'storesuit-customers', 'Customer management' ), 'marketing' => array( 'Marketing', 'Live carts, Waiting customers (back-in-stock requests and searches without results) and URL redirects.', 'megaphone', 'storesuit-marketing', 'Marketing management' ), 'reports' => array( 'Reports', 'Sales, refunds, sales channels and best sellers.', 'chart-bar', 'storesuit-reports', 'More reports' ), 'settings' => array( 'Settings', 'Store details, carriers, email, store health and your license.', 'admin-settings', 'storesuit-settings', 'Store settings' ), 'help' => array( 'Help', 'Guides, quick actions and every feature in one place.', 'editor-help', 'storesuit-guide', 'Help and support' ), ); /** The work areas in menu order; StoreRuler Pro puts its store, stock and B2B areas back in their places. */ public static function areas() : array { $areas = self::AREAS; return $areas; } public static function area( string $url, string $module = '' ) : string { parse_str( (string) wp_parse_url( $url, PHP_URL_QUERY ), $q ); $page = $q['page'] ?? ''; $view = $q['view'] ?? ''; // merchuno-support-v1: Support belongs beside the existing guides. if ( $page === 'storesuit-support' ) { return 'help'; } // StoreRuler Pro's page (ProPage) opens from Help. if ( $page === ProPage::SLUG ) { return 'help'; } $pro = ''; if ( $pro !== '' ) { return $pro; } if ( $page === 'storesuit-customers' ) { return 'customers'; } if ( in_array( $page, array( 'storesuit-marketing', 'storesuit-carts', 'storesuit-stock-alerts', 'storesuit-redirects' ), true ) ) { return 'marketing'; } if ( in_array( $page, array('storesuit-audit', 'storesuit-mail-log'), true ) ) { return 'settings'; } if ( $page === 'storesuit-reports' || $view === 'reports' || $view === 'report' ) { return 'reports'; } if ( preg_match( '/help$/', $page ) || $view === 'help' || in_array( $page, array('storesuit-guide', 'storesuit-modules'), true ) ) { return 'help'; } if ( preg_match( '/(?:settings|targeting|fields|automation)$/', $page ) || $view === 'settings' ) { return 'settings'; } if ( $page === 'storesuit-products' ) { return 'products'; } if ( $pro !== '' ) { return $pro; } return 'sales'; } /** * Merchant journeys join the small engines into one operating system. The free build's words (0.63: no Pro feature * promised); ProScreens::journeys() puts StoreRuler Pro's wording back and adds its journeys and steps. */ public static function journeys() : array { $all = array( array( 'key' => 'catalog', 'name' => 'Prepare a product for sale', 'description' => 'Create the product once, then set its prices and see its stock from the same record.', 'steps' => array(array( 'name' => 'Add the product', 'description' => 'Create a simple product step by step or add options such as colour and size.', 'page' => 'storesuit-products&new=1', 'cap' => 'manage_woocommerce', ), array( 'name' => 'Set prices, check stock', 'description' => 'Set the online and sale price in the product list and see each product\'s stock. Stock is changed in the product\'s WooCommerce editor, on its Inventory tab.', 'page' => 'storesuit-products', 'cap' => 'manage_woocommerce', )), ), array( 'key' => 'order', 'name' => 'Take and complete a sale', 'description' => 'Web store orders keep payment, preparation, and delivery in one order record.', 'steps' => array(array( 'name' => 'Prepare the order', 'description' => 'Follow the next-action badges from a new order through delivery.', 'page' => 'storesuit-orders', 'cap' => 'storesuit_orders', ), array( 'name' => 'Track the payment', 'description' => 'See which orders still have money due and the open balance on each.', 'page' => 'storesuit-orders&queue=payment', 'cap' => 'storesuit_finance', ), array( 'name' => 'Deliver the order', 'description' => 'Record the shipment or the in-person handover on the original order.', 'page' => 'storesuit-orders&queue=fulfil', 'cap' => 'storesuit_fulfil', )), ), array( 'key' => 'customer', 'name' => 'Know your customers', 'description' => 'See each customer\'s orders, open balance, notes, and contact preferences in one place.', 'steps' => array(array( 'name' => 'Find the customer', 'description' => 'View sales history, open balance, and the customer timeline.', 'page' => 'storesuit-customers', 'cap' => 'manage_woocommerce', )), ), array( 'key' => 'control', 'name' => 'Check the business', 'description' => 'Read daily results, sales, stock, and change history using consistent definitions.', 'steps' => array(array( 'name' => 'See today\'s position', 'description' => 'Review sales, receivables, and waiting work together.', 'page' => 'storesuit', 'cap' => 'storesuit_orders', ), array( 'name' => 'Review a period report', 'description' => 'See sales, refunds, and current stock by channel and currency.', 'page' => 'storesuit-reports', 'cap' => 'manage_woocommerce', ), array( 'name' => 'Open the change history', 'description' => 'See who changed what and when.', 'page' => 'storesuit-audit', 'cap' => 'manage_woocommerce', )), ) ); foreach ( $all as &$journey ) { $journey['name'] = I18n::t( $journey['name'] ); $journey['description'] = I18n::t( $journey['description'] ); $journey['steps'] = array_values( array_filter( $journey['steps'], static fn( $step ) => current_user_can( $step['cap'] ) ) ); foreach ( $journey['steps'] as &$step ) { $step['name'] = I18n::t( $step['name'] ); $step['description'] = I18n::t( $step['description'] ); $step['url'] = admin_url( 'admin.php?page=' . $step['page'] ); unset($step['page'], $step['cap']); } unset($step); } unset($journey); return array_values( array_filter( $all, static fn( $journey ) => !empty( $journey['steps'] ) ) ); } /** * The free build's tools that open a WooCommerce screen, by area: a product with options (colour, size...) is made in * WooCommerce's product editor (PLAN-0.63 Q4: the free product form makes simple products). */ private static function free_tools() : array { $tools = array(); if ( current_user_can( 'manage_woocommerce' ) && current_user_can( 'edit_products' ) ) { $tools['products'][] = array( 'name' => I18n::t( 'Add product with options' ), 'url' => admin_url( 'post-new.php?post_type=product' ), 'kind' => 'tool', 'source' => 'StoreRuler', 'description' => I18n::t( 'Create a product with options such as colour and size in the WooCommerce product editor.' ), ); } return $tools; } public static function groups( array $legacy ) : array { $groups = array(); foreach ( self::areas() as $key => $area ) { $groups[$key] = array( 'key' => $key, 'name' => I18n::t( $area[0] ), 'description' => I18n::t( $area[1] ), 'icon' => $area[2], 'url' => admin_url( 'admin.php?page=' . $area[3] ), 'management_label' => I18n::t( $area[4] ), 'children' => array(), ); } // The engines' menu entries ($legacy) and the Pro tools without one are placed by StoreRuler Pro, which also has its own // screens for what the free build leaves to WooCommerce (free_tools()). $tools = self::free_tools(); foreach ( $tools as $area_key => $children ) { if ( isset( $groups[$area_key] ) ) { array_push( $groups[$area_key]['children'], ...$children ); } } // "Where is my order?" (OrderTracking): its settings, in both builds (free since 20 Oct 2026; StoreRuler Pro's tools leave free_tools() out). if ( current_user_can( 'manage_woocommerce' ) ) { $groups['settings']['children'][] = array( 'name' => I18n::t( 'Order tracking' ), 'url' => admin_url( 'admin.php?page=' . OrderTracking::PAGE ), 'kind' => 'settings', 'source' => 'StoreRuler', 'description' => I18n::t( 'A page where customers check their order status.' ), ); } // Hidden WordPress submenus remain discoverable from the area hub and global screen search. foreach ( array('sales', 'marketing') as $area_key ) { foreach ( Guide::daily( $area_key ) as $row ) { $url = admin_url( 'admin.php?page=' . $row[1] ); $exists = false; foreach ( $groups[$area_key]['children'] as $child ) { if ( $child['url'] === $url ) { $exists = true; break; } } if ( !$exists ) { $groups[$area_key]['children'][] = array( 'name' => $row[0], 'url' => $url, 'kind' => 'tool', 'source' => 'StoreRuler', 'description' => $row[3], ); } } } return array_values( array_filter( $groups, static function ( $g ) { return !empty( $g['children'] ) || Guide::daily( $g['key'] ); } ) ); } }