PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.3
WooCommerce v10.9.3
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.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 / Internal / Admin / Orders / PageController.php
woocommerce / src / Internal / Admin / Orders Last commit date
MetaBoxes 2 months ago COTRedirectionController.php 1 year ago Edit.php 1 year ago EditLock.php 1 year ago ListTable.php 4 weeks ago PageController.php 9 months ago PostsRedirectionController.php 9 months ago
PageController.php
587 lines
1 <?php
2 namespace Automattic\WooCommerce\Internal\Admin\Orders;
3
4 use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
5
6 /**
7 * Controls the different pages/screens associated to the "Orders" menu page.
8 */
9 class PageController {
10
11 /**
12 * The order type.
13 *
14 * @var string
15 */
16 private $order_type = '';
17
18 /**
19 * Instance of the posts redirection controller.
20 *
21 * @var PostsRedirectionController
22 */
23 private $redirection_controller;
24
25 /**
26 * Instance of the orders list table.
27 *
28 * @var ListTable
29 */
30 private $orders_table;
31
32 /**
33 * Instance of orders edit form.
34 *
35 * @var Edit
36 */
37 private $order_edit_form;
38
39 /**
40 * Current action.
41 *
42 * @var string
43 */
44 private $current_action = '';
45
46 /**
47 * Order object to be used in edit/new form.
48 *
49 * @var \WC_Order
50 */
51 private $order;
52
53 /**
54 * Verify that user has permission to edit orders.
55 *
56 * @return void
57 */
58 private function verify_edit_permission() {
59 if ( 'edit_order' === $this->current_action && ( ! isset( $this->order ) || ! $this->order ) ) {
60 wp_die( esc_html__( 'You attempted to edit an order that does not exist. Perhaps it was deleted?', 'woocommerce' ) );
61 }
62
63 if ( $this->order->get_type() !== $this->order_type ) {
64 wp_die( esc_html__( 'Order type mismatch.', 'woocommerce' ) );
65 }
66
67 if ( ! current_user_can( get_post_type_object( $this->order_type )->cap->edit_post, $this->order->get_id() ) && ! current_user_can( 'manage_woocommerce' ) ) {
68 wp_die( esc_html__( 'You do not have permission to edit this order.', 'woocommerce' ) );
69 }
70
71 if ( 'trash' === $this->order->get_status() ) {
72 wp_die( esc_html__( 'You cannot edit this item because it is in the Trash. Please restore it and try again.', 'woocommerce' ) );
73 }
74 }
75
76 /**
77 * Verify that user has permission to create order.
78 *
79 * @return void
80 */
81 private function verify_create_permission() {
82 if ( ! current_user_can( get_post_type_object( $this->order_type )->cap->publish_posts ) && ! current_user_can( 'manage_woocommerce' ) ) {
83 wp_die( esc_html__( 'You don\'t have permission to create a new order.', 'woocommerce' ) );
84 }
85
86 if ( isset( $this->order ) ) {
87 $this->verify_edit_permission();
88 }
89 }
90
91 /**
92 * Claims the lock for the order being edited/created (unless it belongs to someone else).
93 * Also handles the 'claim-lock' action which allows taking over the order forcefully.
94 *
95 * @return void
96 */
97 private function handle_edit_lock() {
98 if ( ! $this->order ) {
99 return;
100 }
101
102 $edit_lock = wc_get_container()->get( EditLock::class );
103
104 $locked = $edit_lock->is_locked_by_another_user( $this->order );
105
106 // Take over order?
107 if ( ! empty( $_GET['claim-lock'] ) && wp_verify_nonce( $_GET['_wpnonce'] ?? '', 'claim-lock-' . $this->order->get_id() ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
108 $edit_lock->lock( $this->order );
109 wp_safe_redirect( $this->get_edit_url( $this->order->get_id() ) );
110 exit;
111 }
112
113 if ( ! $locked ) {
114 $edit_lock->lock( $this->order );
115 }
116
117 add_action(
118 'admin_footer',
119 function() use ( $edit_lock ) {
120 $edit_lock->render_dialog( $this->order );
121 }
122 );
123 }
124
125 /**
126 * Sets up the page controller, including registering the menu item.
127 *
128 * @return void
129 */
130 public function setup(): void {
131 global $plugin_page, $pagenow;
132
133 $this->redirection_controller = new PostsRedirectionController( $this );
134
135 // Register menu.
136 if ( 'admin_menu' === current_action() ) {
137 $this->register_menu();
138 } else {
139 add_action( 'admin_menu', 'register_menu', 9 );
140 }
141
142 // Not on an Orders page.
143 if ( empty( $plugin_page ) || 'admin.php' !== $pagenow || 0 !== strpos( $plugin_page, 'wc-orders' ) ) {
144 return;
145 }
146
147 $this->set_order_type();
148 $this->set_action();
149
150 $page_suffix = ( 'shop_order' === $this->order_type ? '' : '--' . $this->order_type );
151 $page_name = ( \WC_Admin_Menus::can_view_woocommerce_menu_item() ? 'woocommerce_page_wc-orders' : 'admin_page_wc-orders' ) . $page_suffix;
152
153 add_action( "load-{$page_name}", array( $this, 'handle_load_page_action' ) );
154 add_action( 'admin_title', array( $this, 'set_page_title' ) );
155 }
156
157 /**
158 * Perform initialization for the current action.
159 *
160 * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed.
161 */
162 public function handle_load_page_action() {
163 $screen = get_current_screen();
164 $screen->post_type = $this->order_type;
165
166 if ( method_exists( $this, 'setup_action_' . $this->current_action ) ) {
167 $this->{"setup_action_{$this->current_action}"}();
168 }
169 }
170
171 /**
172 * Set the document title for Orders screens to match what it would be with the shop_order CPT.
173 *
174 * @param string $admin_title The admin screen title before it's filtered.
175 *
176 * @return string The filtered admin title.
177 *
178 * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed.
179 */
180 public function set_page_title( $admin_title ) {
181 if ( ! $this->is_order_screen( $this->order_type ) ) {
182 return $admin_title;
183 }
184
185 $wp_order_type = get_post_type_object( $this->order_type );
186 $labels = get_post_type_labels( $wp_order_type );
187
188 if ( $this->is_order_screen( $this->order_type, 'list' ) ) {
189 $admin_title = sprintf(
190 // translators: 1: The label for an order type 2: The name of the website.
191 esc_html__( '%1$s &lsaquo; %2$s &#8212; WordPress', 'woocommerce' ),
192 esc_html( $labels->name ),
193 esc_html( get_bloginfo( 'name' ) )
194 );
195 } elseif ( $this->is_order_screen( $this->order_type, 'edit' ) ) {
196 $admin_title = sprintf(
197 // translators: 1: The label for an order type 2: The title of the order 3: The name of the website.
198 esc_html__( '%1$s #%2$s &lsaquo; %3$s &#8212; WordPress', 'woocommerce' ),
199 esc_html( $labels->edit_item ),
200 absint( $this->order->get_id() ),
201 esc_html( get_bloginfo( 'name' ) )
202 );
203 } elseif ( $this->is_order_screen( $this->order_type, 'new' ) ) {
204 $admin_title = sprintf(
205 // translators: 1: The label for an order type 2: The name of the website.
206 esc_html__( '%1$s &lsaquo; %2$s &#8212; WordPress', 'woocommerce' ),
207 esc_html( $labels->add_new_item ),
208 esc_html( get_bloginfo( 'name' ) )
209 );
210 }
211
212 return $admin_title;
213 }
214
215 /**
216 * Determines the order type for the current screen.
217 *
218 * @return void
219 */
220 private function set_order_type() {
221 global $plugin_page;
222
223 $this->order_type = str_replace( array( 'wc-orders--', 'wc-orders' ), '', $plugin_page );
224 $this->order_type = empty( $this->order_type ) ? 'shop_order' : $this->order_type;
225
226 $wc_order_type = wc_get_order_type( $this->order_type );
227 $wp_order_type = get_post_type_object( $this->order_type );
228
229 if ( ! $wc_order_type || ! $wp_order_type || ! $wp_order_type->show_ui || ! current_user_can( $wp_order_type->cap->edit_posts ) ) {
230 wp_die();
231 }
232 }
233
234 /**
235 * Sets the current action based on querystring arguments. Defaults to 'list_orders'.
236 *
237 * @return void
238 */
239 private function set_action(): void {
240 switch ( isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '' ) {
241 case 'edit':
242 $this->current_action = 'edit_order';
243 break;
244 case 'new':
245 $this->current_action = 'new_order';
246 break;
247 default:
248 $this->current_action = 'list_orders';
249 break;
250 }
251 }
252
253 /**
254 * Registers the "Orders" menu.
255 *
256 * @return void
257 */
258 public function register_menu(): void {
259 $order_types = wc_get_order_types( 'admin-menu' );
260
261 foreach ( $order_types as $order_type ) {
262 $post_type = get_post_type_object( $order_type );
263
264 add_submenu_page(
265 \WC_Admin_Menus::can_view_woocommerce_menu_item() ? 'woocommerce' : 'admin.php',
266 $post_type->labels->name,
267 $post_type->labels->menu_name,
268 $post_type->cap->edit_posts,
269 'wc-orders' . ( 'shop_order' === $order_type ? '' : '--' . $order_type ),
270 array( $this, 'output' )
271 );
272 }
273
274 // In some cases (such as if the authoritative order store was changed earlier in the current request) we
275 // need an extra step to remove the menu entry for the menu post type.
276 add_action(
277 'admin_init',
278 function() use ( $order_types ) {
279 foreach ( $order_types as $order_type ) {
280 remove_submenu_page( 'woocommerce', 'edit.php?post_type=' . $order_type );
281 }
282 }
283 );
284 }
285
286 /**
287 * Outputs content for the current orders screen.
288 *
289 * @return void
290 */
291 public function output(): void {
292 switch ( $this->current_action ) {
293 case 'edit_order':
294 case 'new_order':
295 $this->order_edit_form->display();
296 break;
297 case 'list_orders':
298 default:
299 $this->orders_table->prepare_items();
300 $this->orders_table->display();
301 break;
302 }
303 }
304
305 /**
306 * Handles initialization of the orders list table.
307 *
308 * @return void
309 */
310 private function setup_action_list_orders(): void {
311 $this->orders_table = wc_get_container()->get( ListTable::class );
312 $this->orders_table->setup(
313 array(
314 'order_type' => $this->order_type,
315 )
316 );
317
318 if ( $this->orders_table->current_action() ) {
319 $this->orders_table->handle_bulk_actions();
320 }
321
322 $this->strip_http_referer();
323 }
324
325 /**
326 * Perform a redirect to remove the `_wp_http_referer` and `_wpnonce` strings if present in the URL (see also
327 * wp-admin/edit.php where a similar process takes place), otherwise the size of this field builds to an
328 * unmanageable length over time.
329 */
330 private function strip_http_referer(): void {
331 $current_url = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) );
332 $stripped_url = remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), $current_url );
333
334 if ( $stripped_url !== $current_url ) {
335 wp_safe_redirect( $stripped_url );
336 exit;
337 }
338 }
339
340 /**
341 * Prepares the order edit form for creating or editing an order.
342 *
343 * @see \Automattic\WooCommerce\Internal\Admin\Orders\Edit.
344 * @since 8.1.0
345 */
346 private function prepare_order_edit_form(): void {
347 if ( ! $this->order || ! in_array( $this->current_action, array( 'new_order', 'edit_order' ), true ) ) {
348 return;
349 }
350
351 $this->order_edit_form = $this->order_edit_form ?? new Edit();
352 $this->order_edit_form->setup( $this->order );
353 $this->order_edit_form->set_current_action( $this->current_action );
354 }
355
356 /**
357 * Handles initialization of the orders edit form.
358 *
359 * @return void
360 */
361 private function setup_action_edit_order(): void {
362 global $theorder;
363 $this->order = wc_get_order( absint( isset( $_GET['id'] ) ? $_GET['id'] : 0 ) );
364 $this->verify_edit_permission();
365 $this->handle_edit_lock();
366 $theorder = $this->order;
367
368 $this->prepare_order_edit_form();
369 }
370
371 /**
372 * Handles initialization of the orders edit form with a new order.
373 *
374 * @return void
375 */
376 private function setup_action_new_order(): void {
377 global $theorder;
378
379 $this->verify_create_permission();
380
381 $order_class_name = wc_get_order_type( $this->order_type )['class_name'];
382 if ( ! $order_class_name || ! class_exists( $order_class_name ) ) {
383 wp_die();
384 }
385
386 $this->order = new $order_class_name();
387 $this->order->set_object_read( false );
388 $this->order->set_status( 'auto-draft' );
389 $this->order->set_created_via( 'admin' );
390 $this->order->save();
391 $this->handle_edit_lock();
392
393 // Schedule auto-draft cleanup. We re-use the WP event here on purpose.
394 if ( ! wp_next_scheduled( 'wp_scheduled_auto_draft_delete' ) ) {
395 wp_schedule_event( time(), 'daily', 'wp_scheduled_auto_draft_delete' );
396 }
397
398 $theorder = $this->order;
399
400 $this->prepare_order_edit_form();
401 }
402
403 /**
404 * Returns the current order type.
405 *
406 * @return string
407 */
408 public function get_order_type() {
409 return $this->order_type;
410 }
411
412 /**
413 * Helper method to generate a link to the main orders screen.
414 *
415 * @return string Orders screen URL.
416 */
417 public function get_orders_url(): string {
418 return wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ?
419 admin_url( 'admin.php?page=wc-orders' ) :
420 admin_url( 'edit.php?post_type=shop_order' );
421 }
422
423 /**
424 * Helper method to generate edit link for an order.
425 *
426 * @param int $order_id Order ID.
427 *
428 * @return string Edit link.
429 */
430 public function get_edit_url( int $order_id ) : string {
431 if ( ! wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ) {
432 return admin_url( 'post.php?post=' . absint( $order_id ) ) . '&action=edit';
433 }
434
435 $order = wc_get_order( $order_id );
436
437 // Confirm we could obtain the order object (since it's possible it will not exist, due to a sync issue, or may
438 // have been deleted in a separate concurrent request).
439 if ( false === $order ) {
440 wc_get_logger()->debug(
441 sprintf(
442 /* translators: %d order ID. */
443 __( 'Attempted to determine the edit URL for order %d, however the order does not exist.', 'woocommerce' ),
444 $order_id
445 )
446 );
447 $order_type = 'shop_order';
448 } else {
449 $order_type = $order->get_type();
450 }
451
452 try {
453 $base_url = $this->get_base_page_url( $order_type );
454 } catch ( \Exception $e ) {
455 return '';
456 }
457
458 return add_query_arg(
459 array(
460 'action' => 'edit',
461 'id' => absint( $order_id ),
462 ),
463 $base_url
464 );
465 }
466
467 /**
468 * Helper method to generate a link for creating order.
469 *
470 * @param string $order_type The order type. Defaults to 'shop_order'.
471 * @return string
472 */
473 public function get_new_page_url( $order_type = 'shop_order' ) : string {
474 $url = wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ?
475 add_query_arg( 'action', 'new', $this->get_base_page_url( $order_type ) ) :
476 admin_url( 'post-new.php?post_type=' . $order_type );
477
478 return $url;
479 }
480
481 /**
482 * Helper method to generate a link to the main screen for a custom order type.
483 *
484 * @param string $order_type The order type.
485 *
486 * @return string
487 *
488 * @throws \Exception When an invalid order type is passed.
489 */
490 public function get_base_page_url( $order_type ): string {
491 $order_types_with_ui = wc_get_order_types( 'admin-menu' );
492
493 if ( ! in_array( $order_type, $order_types_with_ui, true ) ) {
494 // translators: %s is a custom order type.
495 throw new \Exception( sprintf( __( 'Invalid order type: %s.', 'woocommerce' ), esc_html( $order_type ) ) );
496 }
497
498 return admin_url( 'admin.php?page=wc-orders' . ( 'shop_order' === $order_type ? '' : '--' . $order_type ) );
499 }
500
501 /**
502 * Helper method to check if the current admin screen is related to orders.
503 *
504 * @param string $type Optional. The order type to check for. Default shop_order.
505 * @param string $action Optional. The purpose of the screen to check for. 'list', 'edit', or 'new'.
506 * Leave empty to check for any order screen.
507 *
508 * @return bool
509 */
510 public function is_order_screen( $type = 'shop_order', $action = '' ) : bool {
511 if ( ! did_action( 'current_screen' ) ) {
512 wc_doing_it_wrong(
513 __METHOD__,
514 sprintf(
515 // translators: %s is the name of a function.
516 esc_html__( '%s must be called after the current_screen action.', 'woocommerce' ),
517 esc_html( __METHOD__ )
518 ),
519 '7.9.0'
520 );
521
522 return false;
523 }
524
525 $valid_types = wc_get_order_types( 'view-order' );
526 if ( ! in_array( $type, $valid_types, true ) ) {
527 wc_doing_it_wrong(
528 __METHOD__,
529 sprintf(
530 // translators: %s is the name of an order type.
531 esc_html__( '%s is not a valid order type.', 'woocommerce' ),
532 esc_html( $type )
533 ),
534 '7.9.0'
535 );
536
537 return false;
538 }
539
540 if ( wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ) {
541 if ( $action ) {
542 switch ( $action ) {
543 case 'edit':
544 $is_action = 'edit_order' === $this->current_action;
545 break;
546 case 'list':
547 $is_action = 'list_orders' === $this->current_action;
548 break;
549 case 'new':
550 $is_action = 'new_order' === $this->current_action;
551 break;
552 default:
553 $is_action = false;
554 break;
555 }
556 }
557
558 $type_match = $type === $this->order_type;
559 $action_match = ! $action || $is_action;
560 } else {
561 $screen = get_current_screen();
562
563 if ( $action ) {
564 switch ( $action ) {
565 case 'edit':
566 $screen_match = 'post' === $screen->base && filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
567 break;
568 case 'list':
569 $screen_match = 'edit' === $screen->base;
570 break;
571 case 'new':
572 $screen_match = 'post' === $screen->base && 'add' === $screen->action;
573 break;
574 default:
575 $screen_match = false;
576 break;
577 }
578 }
579
580 $type_match = $type === $screen->post_type;
581 $action_match = ! $action || $screen_match;
582 }
583
584 return $type_match && $action_match;
585 }
586 }
587