PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
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 / Admin / Features / Fulfillments / FulfillmentsController.php
woocommerce / src / Admin / Features / Fulfillments Last commit date
DataStore 1 month ago Providers 3 months ago Fulfillment.php 1 month ago FulfillmentException.php 3 months ago FulfillmentOrderNotes.php 3 months ago FulfillmentUtils.php 2 months ago FulfillmentsController.php 3 months ago FulfillmentsManager.php 2 months ago FulfillmentsRenderer.php 1 month ago FulfillmentsSettings.php 3 months ago FulfillmentsTracker.php 3 months ago OrderFulfillmentsRestController.php 1 month ago ShippingProviders.php 3 months ago
FulfillmentsController.php
264 lines
1 <?php declare(strict_types=1);
2
3 namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
4
5 use Automattic\WooCommerce\Admin\Features\Fulfillments\DataStore\FulfillmentsDataStore;
6 use Automattic\WooCommerce\Internal\Features\FeaturesController;
7 use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
8
9 /**
10 * Class FulfillmentsController
11 *
12 * Base controller for fulfillments management.
13 */
14 class FulfillmentsController {
15 /**
16 * Provides the list of classes that this controller provides.
17 *
18 * @var string[]
19 */
20 private $provides = array(
21 FulfillmentsManager::class,
22 FulfillmentsRenderer::class,
23 FulfillmentsSettings::class,
24 OrderFulfillmentsRestController::class,
25 );
26
27 /**
28 * Initialize the controller.
29 *
30 * @return void
31 */
32 public function register() {
33 add_filter( 'woocommerce_data_stores', array( $this, 'register_data_stores' ) );
34 add_action( 'init', array( $this, 'initialize_fulfillments' ), 10, 0 );
35 }
36
37 /**
38 * Register the fulfillments data store via the woocommerce_data_stores filter.
39 *
40 * This allows extensions to replace the data store with a custom implementation
41 * by filtering 'woocommerce_data_stores' or 'woocommerce_order-fulfillment_data_store'.
42 *
43 * @param array $data_stores Data stores.
44 * @return array
45 */
46 public function register_data_stores( $data_stores ) {
47 if ( ! is_array( $data_stores ) ) {
48 return $data_stores;
49 }
50
51 // Check the option directly instead of using FeaturesController::feature_is_enabled()
52 // because the woocommerce_data_stores filter can fire before the 'init' action
53 // (e.g. from WC Payments during 'plugins_loaded'), and feature_is_enabled() would
54 // trigger translation loading too early, causing _load_textdomain_just_in_time warnings.
55 if ( 'yes' !== get_option( 'woocommerce_feature_fulfillments_enabled', 'no' ) ) {
56 return $data_stores;
57 }
58
59 $data_stores['order-fulfillment'] = FulfillmentsDataStore::class;
60 return $data_stores;
61 }
62
63 /**
64 * Initialize the fulfillments controller.
65 */
66 public function initialize_fulfillments() {
67 $container = wc_get_container();
68 $features_controller = $container->get( FeaturesController::class );
69
70 // If fulfillments feature is not enabled, do not add the DB tables, and don't register the controller.
71 if ( ! $features_controller->feature_is_enabled( 'fulfillments' ) ) {
72 return;
73 }
74
75 // Create the database tables if they do not exist.
76 $this->maybe_create_db_tables();
77
78 // Register the custom shipping providers taxonomy.
79 $this->register_custom_shipping_providers_taxonomy();
80
81 // Register the classes that this controller provides.
82 foreach ( $this->provides as $class ) {
83 $class = $container->get( $class );
84 if ( method_exists( $class, 'register' ) ) {
85 $class->register();
86 }
87 }
88 }
89
90 /**
91 * Register the custom shipping providers taxonomy.
92 */
93 private function register_custom_shipping_providers_taxonomy(): void {
94 if ( taxonomy_exists( 'wc_fulfillment_shipping_provider' ) ) {
95 return;
96 }
97
98 register_taxonomy(
99 'wc_fulfillment_shipping_provider',
100 array(),
101 array(
102 'labels' => array(
103 'name' => __( 'Shipping providers', 'woocommerce' ),
104 'singular_name' => __( 'Shipping provider', 'woocommerce' ),
105 'add_new_item' => __( 'Add new shipping provider', 'woocommerce' ),
106 'edit_item' => __( 'Edit shipping provider', 'woocommerce' ),
107 ),
108 'public' => false,
109 'show_ui' => false,
110 'hierarchical' => false,
111 'show_in_rest' => false,
112 'show_admin_column' => false, // phpcs:ignore WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
113 'show_in_nav_menus' => false, // phpcs:ignore WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
114 'show_tagcloud' => false,
115 'query_var' => false,
116 'rewrite' => false,
117 )
118 );
119 }
120
121 /**
122 * Create the database tables if they do not exist.
123 *
124 * @return void
125 */
126 private function maybe_create_db_tables(): void {
127 global $wpdb;
128
129 if ( get_option( 'woocommerce_fulfillments_db_tables_created', false ) ) {
130 // Verify the tables actually exist (the option may be stale after DB resets in tests).
131 $table_exists = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}wc_order_fulfillments'" );
132 if ( $table_exists ) {
133 return;
134 }
135 }
136
137 // Drop the tables if they exist, to ensure a clean slate.
138 // If one table exists and the other does not, it will be an issue.
139 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}wc_order_fulfillments" );
140 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}wc_order_fulfillment_meta" );
141
142 // Bulk delete order fulfillment status meta from legacy and HPOS order tables.
143 $this->bulk_delete_order_fulfillment_status_meta();
144
145 $collate = '';
146 $container = wc_get_container();
147 $database_util = $container->get( DatabaseUtil::class );
148
149 $max_index_length = $database_util->get_max_index_length();
150 if ( $wpdb->has_cap( 'collation' ) ) {
151 $collate = $wpdb->get_charset_collate();
152 }
153
154 $schema = "CREATE TABLE {$wpdb->prefix}wc_order_fulfillments (
155 fulfillment_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
156 entity_type varchar(255) NOT NULL,
157 entity_id bigint(20) unsigned NOT NULL,
158 status varchar(255) NOT NULL,
159 is_fulfilled tinyint(1) NOT NULL DEFAULT 0,
160 date_updated datetime NOT NULL,
161 date_deleted datetime NULL,
162 PRIMARY KEY (fulfillment_id),
163 KEY entity_type_id (entity_type({$max_index_length}), entity_id)
164 ) $collate;
165 CREATE TABLE {$wpdb->prefix}wc_order_fulfillment_meta (
166 meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
167 fulfillment_id bigint(20) unsigned NOT NULL,
168 meta_key varchar(255) NULL,
169 meta_value longtext NULL,
170 date_updated datetime NOT NULL,
171 date_deleted datetime NULL,
172 PRIMARY KEY (meta_id),
173 KEY meta_key (meta_key({$max_index_length})),
174 KEY fulfillment_id (fulfillment_id)
175 ) $collate;";
176
177 $database_util->dbdelta( $schema );
178
179 // Update the option to indicate that the tables have been created.
180 update_option( 'woocommerce_fulfillments_db_tables_created', true );
181 }
182
183 /**
184 * Bulk delete fulfillment status meta for specific order IDs, or all orders if no order ID specified.
185 *
186 * This method deletes the fulfillment status meta for the specified order IDs from both the legacy postmeta table
187 * and the HPOS meta table.
188 *
189 * @param array<int> $order_ids Array of order IDs to delete fulfillment status meta for.
190 */
191 private function bulk_delete_order_fulfillment_status_meta( $order_ids = array() ): void {
192 $this->delete_legacy_order_fulfillment_meta( $order_ids );
193 $this->delete_hpos_order_fulfillment_meta( $order_ids );
194 }
195
196 /**
197 * Delete fulfillment status meta from legacy postmeta table.
198 *
199 * @param array<int> $order_ids Array of order IDs to delete fulfillment status meta for.
200 */
201 private function delete_legacy_order_fulfillment_meta( $order_ids = array() ) {
202 global $wpdb;
203
204 if ( ! empty( $order_ids ) ) {
205 $order_params = array_merge( array( '_fulfillment_status' ), $order_ids );
206 $wpdb->query(
207 $wpdb->prepare(
208 "DELETE pm FROM {$wpdb->postmeta} pm
209 INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
210 WHERE p.post_type = 'shop_order'
211 AND pm.meta_key = %s
212 AND pm.post_id IN (" . implode( ',', array_fill( 0, count( $order_ids ), '%d' ) ) . ')',
213 ...$order_params
214 )
215 );
216 } else {
217 $wpdb->query(
218 $wpdb->prepare(
219 "DELETE pm FROM {$wpdb->postmeta} pm
220 INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
221 WHERE p.post_type = 'shop_order'
222 AND pm.meta_key = %s",
223 '_fulfillment_status'
224 )
225 );
226 }
227 }
228
229 /**
230 * Delete fulfillment status meta from HPOS meta table.
231 *
232 * @param array<int> $order_ids Array of order IDs to delete fulfillment status meta for.
233 */
234 private function delete_hpos_order_fulfillment_meta( $order_ids = array() ): void {
235 global $wpdb;
236
237 // Check if HPOS meta table exists.
238 $table_name = $wpdb->prefix . 'wc_orders_meta';
239 if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) !== $table_name ) {
240 return;
241 }
242
243 if ( ! empty( $order_ids ) ) {
244 $order_params = array_merge( array( '_fulfillment_status' ), $order_ids );
245 $wpdb->query(
246 $wpdb->prepare(
247 "DELETE FROM {$wpdb->prefix}wc_orders_meta
248 WHERE meta_key = %s
249 AND order_id IN (" . implode( ',', array_fill( 0, count( $order_ids ), '%d' ) ) . ')',
250 ...$order_params
251 )
252 );
253 } else {
254 $wpdb->query(
255 $wpdb->prepare(
256 "DELETE FROM {$wpdb->prefix}wc_orders_meta
257 WHERE meta_key = %s",
258 '_fulfillment_status'
259 )
260 );
261 }
262 }
263 }
264