PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 8.2.0-rc.1
WooCommerce v8.2.0-rc.1
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Admin / PageController.php
woocommerce / src / Admin Last commit date
API 2 years ago BlockTemplates 2 years ago Composer 2 years ago DateTimeProvider 4 years ago Features 2 years ago Marketing 2 years ago Notes 3 years ago Overrides 3 years ago PluginsInstallLoggers 2 years ago PluginsProvider 4 years ago RemoteInboxNotifications 2 years ago Schedulers 4 years ago DataSourcePoller.php 3 years ago DeprecatedClassFacade.php 2 years ago FeaturePlugin.php 4 years ago Loader.php 4 years ago PageController.php 2 years ago PluginsHelper.php 2 years ago PluginsInstaller.php 4 years ago ReportCSVEmail.php 2 years ago ReportCSVExporter.php 3 years ago ReportExporter.php 3 years ago ReportsSync.php 3 years ago WCAdminHelper.php 4 years ago
PageController.php
573 lines
1 <?php
2 /**
3 * PageController
4 */
5
6 namespace Automattic\WooCommerce\Admin;
7
8 use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
9 use Automattic\WooCommerce\Internal\Admin\Loader;
10
11 defined( 'ABSPATH' ) || exit;
12
13 /**
14 * PageController
15 */
16 class PageController {
17 /**
18 * App entry point.
19 */
20 const APP_ENTRY_POINT = 'wc-admin';
21
22 // JS-powered page root.
23 const PAGE_ROOT = 'wc-admin';
24
25 /**
26 * Singleton instance of self.
27 *
28 * @var PageController
29 */
30 private static $instance = false;
31
32 /**
33 * Current page ID (or false if not registered with this controller).
34 *
35 * @var string
36 */
37 private $current_page = null;
38
39 /**
40 * Registered pages
41 * Contains information (breadcrumbs, menu info) about JS powered pages and classic WooCommerce pages.
42 *
43 * @var array
44 */
45 private $pages = array();
46
47 /**
48 * We want a single instance of this class so we can accurately track registered menus and pages.
49 */
50 public static function get_instance() {
51 if ( ! self::$instance ) {
52 self::$instance = new self();
53 }
54
55 return self::$instance;
56 }
57
58 /**
59 * Constructor.
60 * Hooks added here should be removed in `wc_admin_initialize` via the feature plugin.
61 */
62 public function __construct() {
63 add_action( 'admin_menu', array( $this, 'register_page_handler' ) );
64 add_action( 'admin_menu', array( $this, 'register_store_details_page' ) );
65
66 // priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165.
67 add_action( 'admin_head', array( $this, 'remove_app_entry_page_menu_item' ), 20 );
68 }
69
70 /**
71 * Connect an existing page to wc-admin.
72 *
73 * @param array $options {
74 * Array describing the page.
75 *
76 * @type string id Id to reference the page.
77 * @type string|array title Page title. Used in menus and breadcrumbs.
78 * @type string|null parent Parent ID. Null for new top level page.
79 * @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
80 * @type string capability Capability needed to access the page.
81 * @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
82 * @type int position Menu item position.
83 * @type boolean js_page If this is a JS-powered page.
84 * }
85 */
86 public function connect_page( $options ) {
87 if ( ! is_array( $options['title'] ) ) {
88 $options['title'] = array( $options['title'] );
89 }
90
91 /**
92 * Filter the options when connecting or registering a page.
93 *
94 * Use the `js_page` option to determine if registering.
95 *
96 * @param array $options {
97 * Array describing the page.
98 *
99 * @type string id Id to reference the page.
100 * @type string|array title Page title. Used in menus and breadcrumbs.
101 * @type string|null parent Parent ID. Null for new top level page.
102 * @type string screen_id The screen ID that represents the connected page. (Not required for registering).
103 * @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
104 * @type string capability Capability needed to access the page.
105 * @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
106 * @type int position Menu item position.
107 * @type boolean js_page If this is a JS-powered page.
108 * }
109 */
110 $options = apply_filters( 'woocommerce_navigation_connect_page_options', $options );
111
112 // @todo check for null ID, or collision.
113 $this->pages[ $options['id'] ] = $options;
114 }
115
116 /**
117 * Determine the current page ID, if it was registered with this controller.
118 */
119 public function determine_current_page() {
120 $current_url = '';
121 $current_screen_id = $this->get_current_screen_id();
122
123 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
124 $current_url = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
125 }
126
127 $current_query = wp_parse_url( $current_url, PHP_URL_QUERY );
128 parse_str( (string) $current_query, $current_pieces );
129 $current_path = empty( $current_pieces['page'] ) ? '' : $current_pieces['page'];
130 $current_path .= empty( $current_pieces['path'] ) ? '' : '&path=' . $current_pieces['path'];
131
132 foreach ( $this->pages as $page ) {
133 if ( isset( $page['js_page'] ) && $page['js_page'] ) {
134 // Check registered admin pages.
135 if (
136 $page['path'] === $current_path
137 ) {
138 $this->current_page = $page;
139 return;
140 }
141 } else {
142 // Check connected admin pages.
143 if (
144 isset( $page['screen_id'] ) &&
145 $page['screen_id'] === $current_screen_id
146 ) {
147 $this->current_page = $page;
148 return;
149 }
150 }
151 }
152 $this->current_page = false;
153 }
154
155
156 /**
157 * Get breadcrumbs for WooCommerce Admin Page navigation.
158 *
159 * @return array Navigation pieces (breadcrumbs).
160 */
161 public function get_breadcrumbs() {
162 $current_page = $this->get_current_page();
163
164 // Bail if this isn't a page registered with this controller.
165 if ( false === $current_page ) {
166 // Filter documentation below.
167 return apply_filters( 'woocommerce_navigation_get_breadcrumbs', array( '' ), $current_page );
168 }
169
170 if ( 1 === count( $current_page['title'] ) ) {
171 $breadcrumbs = $current_page['title'];
172 } else {
173 // If this page has multiple title pieces, only link the first one.
174 $breadcrumbs = array_merge(
175 array(
176 array( $current_page['path'], reset( $current_page['title'] ) ),
177 ),
178 array_slice( $current_page['title'], 1 )
179 );
180 }
181
182 if ( isset( $current_page['parent'] ) ) {
183 $parent_id = $current_page['parent'];
184
185 while ( $parent_id ) {
186 if ( isset( $this->pages[ $parent_id ] ) ) {
187 $parent = $this->pages[ $parent_id ];
188
189 if ( 0 === strpos( $parent['path'], self::PAGE_ROOT ) ) {
190 $parent['path'] = 'admin.php?page=' . $parent['path'];
191 }
192
193 array_unshift( $breadcrumbs, array( $parent['path'], reset( $parent['title'] ) ) );
194 $parent_id = isset( $parent['parent'] ) ? $parent['parent'] : false;
195 } else {
196 $parent_id = false;
197 }
198 }
199 }
200
201 $woocommerce_breadcrumb = array( 'admin.php?page=' . self::PAGE_ROOT, __( 'WooCommerce', 'woocommerce' ) );
202
203 array_unshift( $breadcrumbs, $woocommerce_breadcrumb );
204
205 /**
206 * The navigation breadcrumbs for the current page.
207 *
208 * @param array $breadcrumbs Navigation pieces (breadcrumbs).
209 * @param array|boolean $current_page The connected page data or false if not identified.
210 */
211 return apply_filters( 'woocommerce_navigation_get_breadcrumbs', $breadcrumbs, $current_page );
212 }
213
214 /**
215 * Get the current page.
216 *
217 * @return array|boolean Current page or false if not registered with this controller.
218 */
219 public function get_current_page() {
220 // If 'current_screen' hasn't fired yet, the current page calculation
221 // will fail which causes `false` to be returned for all subsquent calls.
222 if ( ! did_action( 'current_screen' ) ) {
223 _doing_it_wrong( __FUNCTION__, esc_html__( 'Current page retrieval should be called on or after the `current_screen` hook.', 'woocommerce' ), '0.16.0' );
224 }
225
226 if ( is_null( $this->current_page ) ) {
227 $this->determine_current_page();
228 }
229
230 return $this->current_page;
231 }
232
233
234 /**
235 * Returns the current screen ID.
236 *
237 * This is slightly different from WP's get_current_screen, in that it attaches an action,
238 * so certain pages like 'add new' pages can have different breadcrumbs or handling.
239 * It also catches some more unique dynamic pages like taxonomy/attribute management.
240 *
241 * Format:
242 * - {$current_screen->action}-{$current_screen->action}-tab-section
243 * - {$current_screen->action}-{$current_screen->action}-tab
244 * - {$current_screen->action}-{$current_screen->action} if no tab is present
245 * - {$current_screen->action} if no action or tab is present
246 *
247 * @return string Current screen ID.
248 */
249 public function get_current_screen_id() {
250 $current_screen = get_current_screen();
251 if ( ! $current_screen ) {
252 // Filter documentation below.
253 return apply_filters( 'woocommerce_navigation_current_screen_id', false, $current_screen );
254 }
255
256 $screen_pieces = array( $current_screen->id );
257
258 if ( $current_screen->action ) {
259 $screen_pieces[] = $current_screen->action;
260 }
261
262 if (
263 ! empty( $current_screen->taxonomy ) &&
264 isset( $current_screen->post_type ) &&
265 'product' === $current_screen->post_type
266 ) {
267 // Editing a product attribute.
268 if ( 0 === strpos( $current_screen->taxonomy, 'pa_' ) ) {
269 $screen_pieces = array( 'product_page_product_attribute-edit' );
270 }
271
272 // Editing a product taxonomy term.
273 if ( ! empty( $_GET['tag_ID'] ) ) {
274 $screen_pieces = array( $current_screen->taxonomy );
275 }
276 }
277
278 // Pages with default tab values.
279 $pages_with_tabs = apply_filters(
280 'woocommerce_navigation_pages_with_tabs',
281 array(
282 'wc-reports' => 'orders',
283 'wc-settings' => 'general',
284 'wc-status' => 'status',
285 'wc-addons' => 'browse-extensions',
286 )
287 );
288
289 // Tabs that have sections as well.
290 $wc_emails = \WC_Emails::instance();
291 $wc_email_ids = array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) );
292
293 $tabs_with_sections = apply_filters(
294 'woocommerce_navigation_page_tab_sections',
295 array(
296 'products' => array( '', 'inventory', 'downloadable' ),
297 'shipping' => array( '', 'options', 'classes' ),
298 'checkout' => array( 'bacs', 'cheque', 'cod', 'paypal' ),
299 'email' => $wc_email_ids,
300 'advanced' => array(
301 '',
302 'keys',
303 'webhooks',
304 'legacy_api',
305 'woocommerce_com',
306 ),
307 'browse-extensions' => array( 'helper' ),
308 )
309 );
310
311 if ( ! empty( $_GET['page'] ) ) {
312 $page = wc_clean( wp_unslash( $_GET['page'] ) );
313 if ( in_array( $page, array_keys( $pages_with_tabs ) ) ) {
314 if ( ! empty( $_GET['tab'] ) ) {
315 $tab = wc_clean( wp_unslash( $_GET['tab'] ) );
316 } else {
317 $tab = $pages_with_tabs[ $page ];
318 }
319
320 $screen_pieces[] = $tab;
321
322 if ( ! empty( $_GET['section'] ) ) {
323 $section = wc_clean( wp_unslash( $_GET['section'] ) );
324 if (
325 isset( $tabs_with_sections[ $tab ] ) &&
326 in_array( $section, array_keys( $tabs_with_sections[ $tab ] ) )
327 ) {
328 $screen_pieces[] = $section;
329 }
330 }
331
332 // Editing a shipping zone.
333 if ( ( 'shipping' === $tab ) && isset( $_GET['zone_id'] ) ) {
334 $screen_pieces[] = 'edit_zone';
335 }
336 }
337 }
338
339 /**
340 * The current screen id.
341 *
342 * Used for identifying pages to render the WooCommerce Admin header.
343 *
344 * @param string|boolean $screen_id The screen id or false if not identified.
345 * @param WP_Screen $current_screen The current WP_Screen.
346 */
347 return apply_filters( 'woocommerce_navigation_current_screen_id', implode( '-', $screen_pieces ), $current_screen );
348 }
349
350 /**
351 * Returns the path from an ID.
352 *
353 * @param string $id ID to get path for.
354 * @return string Path for the given ID, or the ID on lookup miss.
355 */
356 public function get_path_from_id( $id ) {
357 if ( isset( $this->pages[ $id ] ) && isset( $this->pages[ $id ]['path'] ) ) {
358 return $this->pages[ $id ]['path'];
359 }
360 return $id;
361 }
362
363 /**
364 * Returns true if we are on a page connected to this controller.
365 *
366 * @return boolean
367 */
368 public function is_connected_page() {
369 $current_page = $this->get_current_page();
370
371 if ( false === $current_page ) {
372 $is_connected_page = false;
373 } else {
374 $is_connected_page = isset( $current_page['js_page'] ) ? ! $current_page['js_page'] : true;
375 }
376
377 // Disable embed on the block editor.
378 $current_screen = did_action( 'current_screen' ) ? get_current_screen() : false;
379 if ( ! empty( $current_screen ) && method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() ) {
380 $is_connected_page = false;
381 }
382
383 /**
384 * Whether or not the current page is an existing page connected to this controller.
385 *
386 * Used to determine if the WooCommerce Admin header should be rendered.
387 *
388 * @param boolean $is_connected_page True if the current page is connected.
389 * @param array|boolean $current_page The connected page data or false if not identified.
390 */
391 return apply_filters( 'woocommerce_navigation_is_connected_page', $is_connected_page, $current_page );
392 }
393
394 /**
395 * Returns true if we are on a page registed with this controller.
396 *
397 * @return boolean
398 */
399 public function is_registered_page() {
400 $current_page = $this->get_current_page();
401
402 if ( false === $current_page ) {
403 $is_registered_page = false;
404 } else {
405 $is_registered_page = isset( $current_page['js_page'] ) && $current_page['js_page'];
406 }
407
408 /**
409 * Whether or not the current page was registered with this controller.
410 *
411 * Used to determine if this is a JS-powered WooCommerce Admin page.
412 *
413 * @param boolean $is_registered_page True if the current page was registered with this controller.
414 * @param array|boolean $current_page The registered page data or false if not identified.
415 */
416 return apply_filters( 'woocommerce_navigation_is_registered_page', $is_registered_page, $current_page );
417 }
418
419 /**
420 * Adds a JS powered page to wc-admin.
421 *
422 * @param array $options {
423 * Array describing the page.
424 *
425 * @type string id Id to reference the page.
426 * @type string title Page title. Used in menus and breadcrumbs.
427 * @type string|null parent Parent ID. Null for new top level page.
428 * @type string path Path for this page, full path in app context; ex /analytics/report
429 * @type string capability Capability needed to access the page.
430 * @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
431 * @type int position Menu item position.
432 * @type int order Navigation item order.
433 * }
434 */
435 public function register_page( $options ) {
436 $defaults = array(
437 'id' => null,
438 'parent' => null,
439 'title' => '',
440 'capability' => 'view_woocommerce_reports',
441 'path' => '',
442 'icon' => '',
443 'position' => null,
444 'js_page' => true,
445 );
446
447 $options = wp_parse_args( $options, $defaults );
448
449 if ( 0 !== strpos( $options['path'], self::PAGE_ROOT ) ) {
450 $options['path'] = self::PAGE_ROOT . '&path=' . $options['path'];
451 }
452
453 if ( null !== $options['position'] ) {
454 $options['position'] = intval( round( $options['position'] ) );
455 }
456
457 if ( is_null( $options['parent'] ) ) {
458 add_menu_page(
459 $options['title'],
460 $options['title'],
461 $options['capability'],
462 $options['path'],
463 array( __CLASS__, 'page_wrapper' ),
464 $options['icon'],
465 $options['position']
466 );
467 } else {
468 $parent_path = $this->get_path_from_id( $options['parent'] );
469 // @todo check for null path.
470 add_submenu_page(
471 $parent_path,
472 $options['title'],
473 $options['title'],
474 $options['capability'],
475 $options['path'],
476 array( __CLASS__, 'page_wrapper' )
477 );
478 }
479
480 $this->connect_page( $options );
481 }
482
483 /**
484 * Get registered pages.
485 *
486 * @return array
487 */
488 public function get_pages() {
489 return $this->pages;
490 }
491
492 /**
493 * Set up a div for the app to render into.
494 */
495 public static function page_wrapper() {
496 Loader::page_wrapper();
497 }
498
499 /**
500 * Connects existing WooCommerce pages.
501 *
502 * @todo The entry point for the embed needs moved to this class as well.
503 */
504 public function register_page_handler() {
505 require_once WC_ADMIN_ABSPATH . 'includes/react-admin/connect-existing-pages.php';
506 }
507
508 /**
509 * Registers the store details (profiler) page.
510 */
511 public function register_store_details_page() {
512 wc_admin_register_page(
513 array(
514 'title' => __( 'Setup Wizard', 'woocommerce' ),
515 'parent' => '',
516 'path' => '/setup-wizard',
517 )
518 );
519 }
520
521 /**
522 * Remove the menu item for the app entry point page.
523 */
524 public function remove_app_entry_page_menu_item() {
525 global $submenu;
526 // User does not have capabilites to see the submenu.
527 if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) {
528 return;
529 }
530
531 $wc_admin_key = null;
532 foreach ( $submenu['woocommerce'] as $submenu_key => $submenu_item ) {
533 // Our app entry page menu item has no title.
534 if ( is_null( $submenu_item[0] ) && self::APP_ENTRY_POINT === $submenu_item[2] ) {
535 $wc_admin_key = $submenu_key;
536 break;
537 }
538 }
539
540 if ( ! $wc_admin_key ) {
541 return;
542 }
543
544 unset( $submenu['woocommerce'][ $wc_admin_key ] );
545 }
546
547 /**
548 * Returns true if we are on a JS powered admin page or
549 * a "classic" (non JS app) powered admin page (an embedded page).
550 */
551 public static function is_admin_or_embed_page() {
552 return self::is_admin_page() || self::is_embed_page();
553 }
554
555 /**
556 * Returns true if we are on a JS powered admin page.
557 */
558 public static function is_admin_page() {
559 // phpcs:disable WordPress.Security.NonceVerification
560 return isset( $_GET['page'] ) && 'wc-admin' === $_GET['page'];
561 // phpcs:enable WordPress.Security.NonceVerification
562 }
563
564 /**
565 * Returns true if we are on a "classic" (non JS app) powered admin page.
566 *
567 * TODO: See usage in `admin.php`. This needs refactored and implemented properly in core.
568 */
569 public static function is_embed_page() {
570 return wc_admin_is_connected_page() || ( ! self::is_admin_page() && class_exists( 'Automattic\WooCommerce\Admin\Features\Navigation\Screen' ) && Screen::is_woocommerce_page() );
571 }
572 }
573