PluginProbe
LitCommerce: Multi-channel Selling Tool For WooCommerce / trunk
LitCommerce: Multi-channel Selling Tool For WooCommerce vtrunk
litcommerce / litcommerce.php

litcommerce.php in LitCommerce: Multi-channel Selling Tool For WooCommerce trunk, at litcommerce.php

727 lines 24.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: LitCommerce: Multi-channel Selling Tool For WooCommerce
4 Description: Helps you easily integrate your WooCommerce store with LitCommerce.
5 Version: 1.3.6
6 Author: LitCommerce
7 Author URI: https://litcommerce.com
8 License: GPL2
9 Text Domain: litcommerce
10 Requires Plugins: woocommerce
11 */
12
13 class LitCommercePlugin {
14 /** @var LitCommerce_Automation[] */
15 public $steps = [];
16
17 public function registerPluginHooks() {
18 if($this->is_multy_app()){
19 add_menu_page('Litcommerce',
20 'Litcommerce',
21 'manage_options',
22 'litcommerce-master',
23 [$this, 'litcommerce_menu_redirect'],
24 plugins_url('images/logo.png', __FILE__),
25 );
26 add_submenu_page(
27 'litcommerce-master',
28 'LitCommerce: Marketplace Integration',
29 'Marketplace Integration',
30 'manage_options',
31 'litcommerce-integration',
32 [$this, 'renderPage']
33 );
34 }else{
35 add_menu_page(
36 'Litcommerce',
37 'Litcommerce',
38 'manage_options',
39 'litcommerce-integration',
40 [$this, 'renderPage'],
41 plugins_url('images/logo.png', __FILE__),
42
43 );
44 }
45
46
47 remove_submenu_page('litcommerce-master', 'litcommerce-master');
48
49 add_action('admin_action_litcommerce_integrate', [$this, 'integrate']);
50 add_action('admin_enqueue_scripts', [$this, 'enqueueScripts']);
51 }
52
53 function is_multy_app(){
54 if (is_plugin_active('litcommerce-feed/litcommerce-feed.php')) {
55 return true;
56 }
57 return false;
58 }
59
60 function integrate() {
61 $stepIndex = filter_input( INPUT_POST, 'step', FILTER_SANITIZE_NUMBER_INT );
62 $result = $this->runStep($stepIndex);
63
64 echo json_encode($result);
65 exit();
66 }
67
68 /**
69 * @param int $stepIndex
70 *
71 * @return LitCommerce_Result_Object
72 */
73 function runStep( $stepIndex ) {
74 if ($stepIndex < 0 || $stepIndex >= count($this->steps)) {
75 return new LitCommerce_Result_Object(
76 false,
77 __('Invalid integration step received. Please contact our support.', 'litcommerce')
78 );
79 }
80
81 return $this->steps[$stepIndex]->runStep();
82 }
83
84 function enqueueScripts() {
85 wp_enqueue_script(
86 'litcommerce-js',
87 plugin_dir_url(__FILE__) . 'js/litcommerce.js',
88 array('jquery'),
89 '0.1',
90 false
91 );
92
93 wp_enqueue_style(
94 'litcommerce-css',
95 plugin_dir_url(__FILE__) . 'css/styles.css',
96 array(),
97 '0.1'
98 );
99 }
100
101 function renderPage() {
102 echo '<h1>LitCommerce: Marketplace Integration</h1>';
103 $is_reconnect = litc_get_params('reconnect') == 1;
104 if (!empty(get_option('woocommerce_litcommerce_consumer_key'))) {
105 $is_connected = true;
106 if ($is_reconnect) {
107
108 $buttonLabel = __('Re-connect to LitCommerce', 'litcommerce');
109 } else {
110 $buttonLabel = __('Go to LitCommerce', 'litcommerce');
111
112 }
113 } else {
114 $is_connected = false;
115 $buttonLabel = __('Connect to LitCommerce', 'litcommerce');
116 }
117
118 ?>
119 <?php if (!$is_connected || $is_reconnect) { ?>
120 <script>
121 var litcommerceBaseUrl = <?php echo json_encode(admin_url('admin.php')); ?>;
122 var litcommerceStoreUrl = <?php echo json_encode(home_url()); ?>;
123 var integrationStepCount = <?php echo json_encode(count($this->steps)); ?>;
124 var defaultIntegrationError = <?php echo json_encode(__('Could not connect to the website to complete the integration step. Please, try again.', 'litcommerce')) ?>;
125 var successfulIntegrationMessage = <?php echo json_encode(__('Successfully prepared to integrate with Litcommerce!', 'litcommerce')) ?>;
126 </script>
127 <div id="litcommerce-description">
128 <p>Easily activate Litcommerce Integration with WooCommerce. Connect Litcommerce and WooCommerce on your
129 website
130 with a single click of the button below.</p>
131 <p>By clicking the button below, you are acknowledging that Litcommerce can make the following
132 changes:</p>
133 <ul style="list-style: circle inside;">
134 <?php foreach ($this->steps as $index => $step) { ?>
135 <li><?php echo esc_textarea($step->getName()); ?></li>
136 <?php } ?>
137 </ul>
138 <form method="post" action="<?php echo esc_url(admin_url('admin.php')); ?>" novalidate="novalidate">
139 <p class="submit">
140 <input type="hidden" name="action" value="litcommerce_integrate"/>
141 <input type="hidden" name="step" value="0"/>
142 <input type="submit" value="<?php echo esc_attr($buttonLabel); ?>" class="button button-primary"
143 id="btn-submit">
144 </p>
145 </form>
146 </div>
147 <div id="litcommerce-progress" style="display: none">
148 Integration progress:
149 <ol>
150 <?php foreach ($this->steps as $index => $step) { ?>
151 <li id="litcommerce-step-<?php echo esc_textarea($index); ?>">
152 <?php echo esc_textarea($step->getName()); ?>
153 </li>
154 <?php } ?>
155 </ol>
156 <p id="litcommerce-result">
157 </p>
158 </div>
159 <?php if (litc_get_params('reconnect') == 1) { ?>
160 <script>
161 var link = document.getElementById('btn-submit');
162 link.click()
163 </script>
164 <?php } ?>
165 <?php } else { ?>
166 <a type="submit" href="https://app.litcommerce.com" target="_blank" class="button button-primary"
167 id="btn-submit"><?php echo esc_attr($buttonLabel); ?></a>
168 <?php
169 $url = site_url() . '/wp-admin/admin.php?page=litcommerce-integration&reconnect=1'
170 ?>
171 <p style="font-style: italic">If your site is not yet connected to LitCommerce, please <a
172 href="<?php echo esc_url($url); ?>">click here</a> to reconnect</p>
173 <?php } ?>
174 <p style="font-style: italic"> If you are using the Cloudflare Web Application Firewall, please follow <a
175 href="https://help.litcommerce.com/en/article/solution-when-your-websites-firewall-blocks-litcommerce-i2ub8p/"
176 target="_blank">these instructions</a> to establish a connection.</p>
177
178 <?php
179 }
180 }
181
182 include_once('LitCommerceResultObject.php');
183 include_once('steps/LitCommerce_Automation.php');
184 include_once('steps/EnsureWooCommercePlugin.php');
185 include_once('steps/EnsureWooCommerceActive.php');
186 include_once('steps/EnableWooCommerceAPI.php');
187 include_once('steps/PermalinkSettings.php');
188 include_once('steps/GenerateWooCommerceKeys.php');
189 include_once('steps/SendWooCommerceKeys.php');
190
191 $litcommercePlugin = new LitCommercePlugin();
192 $litcommercePlugin->steps[] = new LitCommerce_EnsureWooCommercePlugin();
193 $litcommercePlugin->steps[] = new LitCommerce_EnsureWooCommerceActive();
194 $litcommercePlugin->steps[] = new LitCommerce_EnableWooCommerceAPI();
195 $litcommercePlugin->steps[] = new LitCommerce_PermalinkSettings();
196 $litcommercePlugin->steps[] = new LitCommerce_GenerateWooCommerceKeys();
197 $litcommercePlugin->steps[] = new LitCommerce_SendWooCommerceKeysStep();
198
199 add_action('admin_menu', [$litcommercePlugin, 'registerPluginHooks']);
200 add_filter('woocommerce_rest_product_object_query', function ( array $args, \WP_REST_Request $request ) {
201 $modified_after = litc_get_params('modified_after');
202
203 if (!$modified_after) {
204 return $args;
205 }
206 $args['date_query'][] = [
207 "column" => "post_modified",
208 "after" => $modified_after,
209 ];
210 $fields = [
211 'order' => 'litcommerce',
212 'orderby' => 'litcommerceby',
213 'offset' => 'litcommerceoff',
214 'paged' => 'litcommercepag',
215 ];
216 foreach ($fields as $field => $param) {
217 if (litc_get_params($param)) {
218 $args[$field] = litc_get_params($param);
219 }
220 }
221 if ('date' === $args['orderby']) {
222 $args['orderby'] = 'date ID';
223 }
224 return $args;
225
226 }, 10, 2);
227 add_filter('woocommerce_rest_shop_order_object_query', function ( array $args, \WP_REST_Request $request ) {
228 $modified_after = litc_get_params('modified_after');
229
230 if (!$modified_after) {
231 return $args;
232 }
233 $args['date_query'][] = [
234 "column" => "post_modified",
235 "after" => $modified_after,
236 ];
237 $fields = [
238 'order' => 'litcommerce',
239 'orderby' => 'litcommerceby',
240 'offset' => 'litcommerceoff',
241 'paged' => 'litcommercepage',
242 ];
243 foreach ($fields as $field => $param) {
244 if (litc_get_params($param)) {
245 $args[$field] = litc_get_params($param);
246 }
247 }
248 return $args;
249
250 }, 10, 2);
251 // ADDING 2 NEW COLUMNS WITH THEIR TITLES (keeping "Total" and "Actions" columns at the end)
252 add_filter('manage_edit-shop_order_columns', 'litc_custom_shop_order_column', 20);
253 function litc_custom_shop_order_column( $columns ) {
254 $reordered_columns = array();
255
256 // Inserting columns to a specific location
257 foreach ($columns as $key => $column) {
258 $reordered_columns[$key] = $column;
259 if ($key == 'order_status') {
260 // Inserting after "Status" column
261 $reordered_columns['_litc_order_from'] = __('Source', 'litcommerce');
262 $reordered_columns['_litc_order_number'] = __('LitC Order Number', 'litcommerce');
263 }
264 }
265 return $reordered_columns;
266 }
267 add_filter('manage_woocommerce_page_wc-orders_columns', 'litc_custom_shop_order_column', 20);
268
269 // Adding custom fields meta data for each new column (example)
270 add_action('manage_woocommerce_page_wc-orders_custom_column', 'litc_new_custom_orders_list_column_content', 20, 2);
271 function litc_new_custom_orders_list_column_content( $column, $order ) {
272 switch ($column) {
273 case '_litc_order_from' :
274
275 // Get custom post meta data
276 $column_data = $order->get_meta('_litc_order_from');
277 if (!empty($column_data))
278 echo esc_textarea($column_data);
279
280 // Testing (to be removed) - Empty value case
281 else
282 echo '';
283
284 break;
285 case '_litc_order_number' :
286 $column_data = $order->get_meta('_litc_order_number');
287
288 if ($column_data) {
289 $litc_order_id = $order->get_meta('_litc_order_id');
290 if ($litc_order_id) {
291 echo '<a href="' . esc_url("https://app.litcommerce.com/orders/{$litc_order_id}") . '" target="_blank">' . esc_html($column_data) . '</a>';
292 } else {
293 echo esc_textarea($column_data);
294 }
295 } else {
296 echo '';
297 }
298
299 }
300 }
301 // Adding custom fields meta data for each new column (example)
302 add_action('manage_shop_order_posts_custom_column', 'litc_custom_orders_list_column_content', 20, 2);
303 function litc_custom_orders_list_column_content( $column, $post_id ) {
304 switch ($column) {
305 case '_litc_order_from' :
306
307 // Get custom post meta data
308 $column_data = get_post_meta($post_id, $column, true);
309 if (!empty($column_data))
310 echo esc_textarea($column_data);
311
312 // Testing (to be removed) - Empty value case
313 else
314 echo '';
315
316 break;
317 case '_litc_order_number' :
318 $column_data = get_post_meta($post_id, $column, true);
319 if ($column_data) {
320 $litc_order_id = get_post_meta($post_id, '_litc_order_id', true);
321 if ($litc_order_id) {
322 echo '<a href="' . esc_url("https://app.litcommerce.com/orders/{$litc_order_id}") . '" target="_blank">' . esc_html($column_data) . '</a>';
323
324 } else {
325 echo esc_textarea($column_data);
326 }
327 } else {
328 echo '';
329 }
330
331 }
332 }
333
334 function litc_filter_woocommerce_customer_email_recipient( $recipient, $order, $email ) {
335 if (!$order || !is_a($order, 'WC_Order'))
336 return $recipient;
337
338 // Has order status
339 $column_data = get_post_meta($order->get_id(), '_litc_allow_send_email', true);
340 if ($column_data && $column_data != 1) {
341 return '';
342 }
343
344 return $recipient;
345 }
346
347 function litc_filter_woocommerce_owner_email_recipient( $recipient, $order, $email ) {
348 if (!$order || !is_a($order, 'WC_Order'))
349 return $recipient;
350
351 // Has order status
352 $column_data = get_post_meta($order->get_id(), '_litc_allow_send_email_owner', true);
353 if ($column_data && $column_data != 1) {
354 return '';
355 }
356
357 return $recipient;
358 }
359
360 add_filter('woocommerce_email_recipient_customer_refunded_order', 'litc_filter_woocommerce_customer_email_recipient', 10, 3);
361 add_filter('woocommerce_email_recipient_customer_on_hold_order', 'litc_filter_woocommerce_customer_email_recipient', 10, 3);
362 add_filter('woocommerce_email_recipient_customer_processing_order', 'litc_filter_woocommerce_customer_email_recipient', 10, 3);
363 add_filter('woocommerce_email_recipient_new_order', 'litc_filter_woocommerce_owner_email_recipient', 10, 3);
364 add_filter('woocommerce_email_recipient_customer_cancelled_order', 'litc_filter_woocommerce_customer_email_recipient', 10, 3);
365 add_filter('woocommerce_email_recipient_failed_order', 'litc_filter_woocommerce_owner_email_recipient', 10, 3);
366 add_filter('woocommerce_email_recipient_customer_completed_order', 'litc_filter_woocommerce_customer_email_recipient', 10, 3);
367 function litc_change_woocommerce_order_number( $order_id, $order ) {
368 $meta_data = $order->get_meta_data();
369 $order_number = $order_id;
370 $order_number_prefix = '';
371 $order_number_suffix = '';
372 $custom_order_number = '';
373 $keep_woo_order_number = false;
374 foreach ($meta_data as $item) {
375 if($keep_woo_order_number){
376 return $order_id;
377 }
378 switch ($item->get_data()['key']) {
379 case '_litc_keep_woo_order_number':
380 $keep_woo_order_number = true;
381 break;
382 case '_litc_order_number':
383 $order_number = $item->get_data()['value'];
384 break;
385 // case '_order_number':
386 // $custom_order_number = $item->get_data()['value'];
387 // break;
388 case '_litc_order_number_prefix':
389 $order_number_prefix = $item->get_data()['value'];
390 break;
391 case '_litc_order_number_suffix':
392 $order_number_suffix = $item->get_data()['value'];
393 break;
394
395 }
396 }
397 return $custom_order_number? $custom_order_number: $order_number_prefix . $order_number . $order_number_suffix;
398 }
399
400 add_filter('woocommerce_order_number', 'litc_change_woocommerce_order_number', PHP_INT_MAX, 2);
401 function litc_shop_order_meta_search_fields( $meta_keys ) {
402 $meta_keys[] = '_litc_order_number';
403 return $meta_keys;
404 }
405
406 add_filter('woocommerce_shop_order_search_fields', 'litc_shop_order_meta_search_fields', 10, 1);
407 add_filter( 'woocommerce_order_table_search_query_meta_keys', 'litc_shop_order_meta_search_fields' );
408
409 function litc_woocommerce_rest_prepare_product_object( $response, $object, $request ) {
410 if (litc_get_params("custom_currency") == 1) {
411 $meta = get_post_meta($object->get_id());
412 foreach ($meta as $key => $value) {
413 if (in_array($key, ['_price', '_regular_price', '_sale_price'])) {
414 $response->data['litc' . $key] = $value[0];
415 }
416 }
417 }
418
419 if (litc_get_params("get_terms")) {
420 $terms = explode(',', litc_get_params("get_terms"));
421 foreach ($terms as $term) {
422 $terms_data = wp_get_post_terms($object->get_id(), $term);
423 $res = [];
424 if ($terms_data) {
425 $res[] = $terms_data[0]->name;
426 }
427 if ($res) {
428 $response->data['litc_' . $term] = implode(',', $res);
429 }
430 }
431 }
432 if(@$response->data['meta_data']){
433 foreach ($response->data['meta_data'] as $meta_data) {
434 if ($meta_data->key == '_yoast_wpseo_primary_yith_product_brand') {
435 $brand_id = $meta_data->value;
436 $terms_data = get_term_by('id', $brand_id, 'yith_product_brand');
437 try {
438 if ($terms_data) {
439 $response->data['litc_product_brand'] = $terms_data->name;
440 break;
441 }
442 } catch (Exception $e) {
443
444 }
445
446
447 }
448 }
449 }
450
451 return $response;
452 }
453
454 add_filter('woocommerce_rest_prepare_product_object', 'litc_woocommerce_rest_prepare_product_object', 10, 3);
455 add_filter('woocommerce_rest_prepare_product_variation_object', 'litc_woocommerce_rest_prepare_product_object', 10, 3);
456 add_action('woocommerce_admin_order_item_headers', 'litc_admin_order_items_headers', 10, 1);
457 function litc_admin_order_items_headers( $order ) {
458 if (is_object($order) && method_exists($order, 'get_meta') && $order->get_meta('_litc_has_tax')) {
459
460 echo '<th class="line_litc_tax_line sortable" data-sort="float">
461 Tax
462 </th>';
463 }
464
465
466 }
467
468 add_action('woocommerce_admin_order_item_values', 'litc_admin_order_item_values', 10, 3);
469 function litc_admin_order_item_values( $_product, $item, $item_id = null ) {
470
471 // get the post meta value from the associated product
472 $value = $item->get_meta('_litc_item_tax');
473 $order = $item->get_order();
474 if (is_object($order) && method_exists($order, 'get_meta') && $order->get_meta('_litc_has_tax')) {
475 $currency = $order->get_currency();
476 $amount = (float) $value;
477 if ($value) {
478 echo '<td class="item_cost" width="1%" data-sort-value="float">
479 <div class="view">' .
480 wc_price( $amount, [ 'currency' => $currency ] ) .
481 '</div>
482 </td>';;
483 } else {
484 echo '<td></td>';
485 }
486 }
487
488 //
489 // display the value
490
491 }
492 function litc_get_params($key)
493 {
494 $value = filter_input(INPUT_GET, $key, FILTER_SANITIZE_SPECIAL_CHARS);
495 if(!$value){
496 return null;
497 }
498 return $value;
499 }
500
501 function litc_woocommerce_hidden_order_itemmeta( $arr ) {
502 $arr[] = '_litc_item_tax';
503 $arr[] = '_litc_order_id';
504 return $arr;
505 }
506
507 add_filter('woocommerce_hidden_order_itemmeta', 'litc_woocommerce_hidden_order_itemmeta', 10, 1);
508 function litc_woocommerce_find_rates( $matched_tax_rates ) {
509 if (litc_get_params('from_litc') == 1 && litc_get_params('litc_custom_tax_rate')) {
510 return [
511 0 => [
512 'rate' => litc_get_params('litc_custom_tax_rate'),
513 'label' => litc_get_params('litc_custom_tax_label') ? litc_get_params('litc_custom_tax_label') : 'Tax',
514 'shipping' => litc_get_params('litc_custom_shipping_tax') == 1 ? 'yes' : 'no',
515 'compound' => 'no'
516 ]
517 ];
518 }
519 return $matched_tax_rates;
520
521
522 }
523
524
525
526
527
528 add_filter('woocommerce_find_rates', 'litc_woocommerce_find_rates', 10, 3);
529 function litc_woocommerce_rate_label( $rate_name ) {
530 if ($litc_custom_tax_label = litc_get_params('litc_custom_tax_label')) {
531 return $litc_custom_tax_label;
532 }
533 return $rate_name;
534
535
536 }
537
538 add_filter('woocommerce_rate_label', 'litc_woocommerce_rate_label', 10, 3);
539 function litc_woocommerce_rest_pre_insert_shop_order_object( $order ) {
540 if(litc_get_params('from_litc') == 1 && class_exists('WC_Seq_Order_Number')){
541 global $wpdb;
542 $using_hpos = class_exists( \Automattic\WooCommerce\Utilities\OrderUtil::class ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
543 $order_meta_table = $using_hpos ? $wpdb->prefix . 'wc_orders_meta' : $wpdb->postmeta;
544 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
545 $max_order_number = $wpdb->get_row($wpdb->prepare(
546 "SELECT IF( MAX( CAST( meta_value as UNSIGNED ) ) IS NULL, 1, MAX( CAST( meta_value as UNSIGNED ) ) + 1 ) as max_order_number
547 FROM %i
548 WHERE meta_key = %s",
549 $order_meta_table,
550 '_order_number'
551 ), ARRAY_A);
552 if($max_order_number){
553 $order->update_meta_data( '_order_number', $max_order_number['max_order_number']);
554
555 }
556 }
557
558 return $order;
559
560
561 }
562
563 add_filter('woocommerce_rest_pre_insert_shop_order_object', 'litc_woocommerce_rest_pre_insert_shop_order_object', 10);
564
565
566 add_action('rest_api_init', function () {
567 register_rest_route('wc/v3/litc', '/products/(?P<id>\d+)/images', array(
568 'methods' => 'POST',
569 'callback' => 'litc_add_product_images',
570 'permission_callback' => function () {
571 return current_user_can('edit_products');
572 },
573 ));
574 register_rest_route('wc/v3/litc', '/products/(?P<product_id>\d+)/images/(?P<image_id>\d+)', array(
575 'methods' => 'DELETE',
576 'callback' => 'litc_delete_product_image',
577 'permission_callback' => function () {
578 return current_user_can('edit_products');
579 },
580 ));
581 });
582
583 function litc_add_product_images($request) {
584 $product_id = $request['id'];
585 $images = $request->get_param('images');
586
587 if (!is_array($images) || empty($images)) {
588 return new WP_Error('invalid_images', 'Invalid images array', array('status' => 400));
589 }
590
591 if (!get_post($product_id) || get_post_type($product_id) !== 'product') {
592 return new WP_Error('invalid_product', 'Product not found', array('status' => 404));
593 }
594
595 $uploaded_images = [];
596
597 foreach ($images as $image_url) {
598 $image_id = litc_upload_image_from_url($image_url);
599
600 if (is_wp_error($image_id)) {
601 return new WP_Error('image_upload_failed', 'Failed to upload image: ' . $image_url, array('status' => 500));
602 }
603
604 $uploaded_images[] = $image_id;
605 }
606
607 $product = wc_get_product($product_id);
608 $existing_gallery = $product->get_gallery_image_ids();
609 $updated_gallery = array_merge($existing_gallery, $uploaded_images);
610 $product->set_gallery_image_ids($updated_gallery);
611 $product->save();
612
613 return rest_ensure_response([
614 'success' => true,
615 'uploaded_images' => $uploaded_images,
616 ]);
617 }
618 function litc_generate_random_string($length = 10) {
619 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
620 $charactersLength = strlen($characters);
621 $randomString = '';
622
623 for ($i = 0; $i < $length; $i++) {
624 $randomString .= $characters[random_int(0, $charactersLength - 1)];
625 }
626
627 return $randomString;
628 }
629 function litc_upload_image_from_url($image_url) {
630 $upload_dir = wp_upload_dir();
631 $image_data = file_get_contents($image_url);
632
633 if (!$image_data) {
634 return new WP_Error('image_fetch_failed', 'Could not fetch image from URL.');
635 }
636
637 $filename = basename($image_url);
638 $filename = time() . '_' .explode('?', $filename)[0];
639 if(strlen($filename) > 200){
640 $filename_exp = explode('.', $filename);
641 $filename = litc_generate_random_string(5) . time() . '.' . end($filename_exp);
642 }
643 $file_path = $upload_dir['path'] . '/' . $filename;
644
645 file_put_contents($file_path, $image_data);
646
647 $filetype = wp_check_filetype($filename, null);
648
649 if (!$filetype['type']) {
650 return new WP_Error('invalid_image_type', 'Invalid image type.');
651 }
652
653 $attachment_id = wp_insert_attachment(
654 [
655 'guid' => $upload_dir['url'] . '/' . $filename,
656 'post_mime_type' => $filetype['type'],
657 'post_title' => sanitize_file_name($filename),
658 'post_content' => '',
659 'post_status' => 'inherit',
660 ],
661 $file_path
662 );
663
664 require_once(ABSPATH . 'wp-admin/includes/image.php');
665 // wp_generate_attachment_metadata() calls wp_read_video_metadata()/wp_read_audio_metadata()
666 // for non-image files, and both live in wp-admin/includes/media.php, which is not loaded
667 // during a REST request. Without this the call is fatal and leaves an orphaned attachment.
668 require_once(ABSPATH . 'wp-admin/includes/media.php');
669 $attach_data = wp_generate_attachment_metadata($attachment_id, $file_path);
670 wp_update_attachment_metadata($attachment_id, $attach_data);
671
672 return $attachment_id;
673 }
674
675
676 function litc_delete_product_image($request) {
677 $product_id = $request['product_id'];
678 $image_id = $request['image_id'];
679 $force = $request->get_param('force');
680 if (!get_post($product_id) || get_post_type($product_id) !== 'product') {
681 return new WP_Error('invalid_product', 'Product not found', array('status' => 404));
682 }
683
684 if (!get_post($image_id)) {
685 return new WP_Error('invalid_image', 'Image not found', array('status' => 404));
686 }
687
688 $product = wc_get_product($product_id);
689 $gallery = $product->get_gallery_image_ids();
690
691 if (!in_array($image_id, $gallery)) {
692 return new WP_Error('image_not_in_product', 'Image is not associated with this product.', array('status' => 400));
693 }
694
695 $updated_gallery = array_diff($gallery, [$image_id]);
696 $product->set_gallery_image_ids($updated_gallery);
697 $product->save();
698
699 if ($force === true || $force === 'true') {
700 wp_delete_attachment($image_id, true);
701 }
702
703
704 return rest_ensure_response([
705 'success' => true,
706 'message' => 'Image removed from product successfully.',
707 'remaining_images' => $updated_gallery,
708 ]);
709 }
710
711 add_filter( 'woocommerce_can_restore_order_stock', 'litc_conditional_no_restore_stock', 10, 2 );
712
713 function litc_conditional_no_restore_stock( $can_restore, $order ) {
714 if ( ! $order instanceof WC_Order ) {
715 return $can_restore;
716 }
717
718 if ( $order->get_status() === 'cancelled' || $order->get_status() === 'refunded') {
719 $no_restore = $order->get_meta( 'litc_order_no_restore_stock' );
720
721 if ( $no_restore == '1' || $no_restore === 'yes' ) {
722 return false;
723 }
724 }
725
726 return $can_restore;
727 }