PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.4.1
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.4.1
3.0.3 3.0.2 3.0.1 trunk 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.3.0 2.3.1 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.91 2.7.92 2.7.93 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0
commercebird / includes / woo-functions.php
commercebird / includes Last commit date
classes 1 year ago sync 1 year ago index.php 1 year ago woo-functions.php 1 year ago
woo-functions.php
735 lines
1 <?php
2
3 /**
4 * All WooCommerce related functions.
5 *
6 * @category WooCommerce
7 * @package CommerceBird
8 * @author Fawad Tiemoerie <info@roadmapstudios.com>
9 * @license GNU General Public License v3.0
10 * @link https://commercebird.com
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Helper functions to ensure correct handling of Data being transferred via rest api
19 */
20
21 function cmbird_clear_product_cache( $object, $request, $is_creating ) {
22 if ( $is_creating ) {
23 $product_id = $object->get_id();
24 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
25 $cmbird_zi_product_sync = get_option( 'cmbird_zoho_disable_product_sync_status' );
26 if ( ! empty( $zoho_inventory_access_token ) && ! $cmbird_zi_product_sync ) {
27 // if request contain meta zi_item_id, then return
28 if ( isset( $request['meta']['zi_item_id'] ) ) {
29 return;
30 }
31 $product_handler = new CMBIRD_Products_ZI_Export();
32 $product_handler->cmbird_zi_product_sync( $product_id );
33 }
34
35 // Sync to Zoho CRM as well
36 $zoho_crm_access_token = get_option( 'cmbird_zoho_crm_access_token' );
37 if ( ! empty( $zoho_crm_access_token ) ) {
38 $cmbird_zcrm_product_sync = get_option( 'cmbird_zoho_crm_disable_product_sync_status' );
39 if ( ! $cmbird_zcrm_product_sync ) {
40 $product = wc_get_product( $product_id );
41 if ( $product ) {
42 $zcrm_product_handler = new CMBIRD_ZCRM_Product();
43 $zcrm_product_handler->cmbird_sync_product_to_zoho( $product );
44 }
45 }
46 }
47
48 wc_delete_product_transients( $product_id );
49 }
50 }
51 add_action( 'woocommerce_rest_insert_product_object', 'cmbird_clear_product_cache', 10, 3 );
52
53
54
55 /**
56 * Function to update the Contact in Zoho when customer updates address on frontend
57 * @param $user_id
58 */
59 function cmbird_update_contact_via_accountpage( $user_id ) {
60 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
61 if ( ! empty( $zoho_inventory_access_token ) ) {
62 $contact_class_handle = new CMBIRD_Contact_ZI();
63 $contact_class_handle->cmbird_contact_update_function( $user_id );
64
65 global $wpdb;
66 $meta_key_search = 'zi_contact_person_id%';
67 $query = $wpdb->get_results(
68 $wpdb->prepare(
69 "SELECT meta_key, meta_value
70 FROM {$wpdb->usermeta}
71 WHERE user_id = %d
72 AND meta_key LIKE %s",
73 $user_id,
74 $meta_key_search
75 )
76 );
77 if ( ! empty( $query ) ) {
78 // Usermeta keys containing 'zi_contact_person_id' exist.
79 foreach ( $query as $row ) {
80 $contact_class_handle->cmbird_update_contact_person( $user_id, $row->meta_value );
81 }
82 } else {
83 return;
84 }
85 } else {
86 return;
87 }
88 }
89 add_action( 'profile_update', 'cmbird_update_contact_via_accountpage' );
90
91 /**
92 * Function to be called by hook when new product is added in WooCommerce.
93 *
94 * @param $product_id
95 * @return void
96 */
97 add_action( 'woocommerce_update_product', 'cmbird_zi_product_sync_class', 10, 1 );
98 add_action( 'woocommerce_new_product', 'cmbird_zi_product_sync_class', 10, 1 );
99 add_action( 'wp_ajax_zoho_admin_product_sync', 'cmbird_zi_product_sync_class' );
100 function cmbird_zi_product_sync_class( $product_id ) {
101 if ( ! is_admin() ) {
102 return;
103 }
104 if ( ! $product_id ) {
105 // Check nonce for security
106 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'zoho_admin_product_sync' ) ) {
107 wp_send_json_error( 'Nonce verification failed' );
108 } else {
109 $product_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
110 if ( ! $product_id ) {
111 wp_send_json_error( 'Invalid Product ID' );
112 }
113 }
114 }
115 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
116 $cmbird_zi_product_sync = get_option( 'cmbird_zoho_disable_product_sync_status' );
117 if ( ! $cmbird_zi_product_sync && $zoho_inventory_access_token ) {
118 $product_handler = new CMBIRD_Products_ZI_Export();
119 $product_handler->cmbird_zi_product_sync( $product_id );
120 }
121
122 // Sync to Zoho CRM as well
123 $zoho_crm_access_token = get_option( 'cmbird_zoho_crm_access_token' );
124 if ( ! empty( $zoho_crm_access_token ) ) {
125 $cmbird_zcrm_product_sync = get_option( 'cmbird_zoho_crm_disable_product_sync_status' );
126 if ( ! $cmbird_zcrm_product_sync ) {
127 $product = wc_get_product( $product_id );
128 if ( $product ) {
129 $zcrm_product_handler = new CMBIRD_ZCRM_Product();
130 $sync_result = $zcrm_product_handler->cmbird_sync_product_to_zoho( $product );
131
132 // Handle different response types based on product type
133 if ( $product->is_type( 'variable' ) && is_array( $sync_result ) ) {
134 // Variable product returns array with details
135 $success_count = $sync_result['success_count'];
136 $failed_count = $sync_result['failed_count'];
137 $parent_id = $sync_result['parent_product_id'];
138
139 // If parent_id is not in result, get it from post meta (for existing products)
140 if ( ! $parent_id ) {
141 $parent_id = get_post_meta( $product_id, 'zcrm_product_id', true );
142 }
143
144 if ( $success_count > 0 ) {
145 update_post_meta( $product_id, 'zcrm_product_sync_status', 'success' );
146 $message = sprintf(
147 'Variable product synced: %d successful, %d failed. Parent ID: %s',
148 $success_count,
149 $failed_count,
150 $parent_id ? $parent_id : 'N/A'
151 );
152 update_post_meta( $product_id, 'zcrm_product_sync_message', $message );
153 } else {
154 update_post_meta( $product_id, 'zcrm_product_sync_status', 'failed' );
155 update_post_meta( $product_id, 'zcrm_product_sync_message', 'Failed to sync variable product and variations to Zoho CRM' );
156 }
157 } elseif ( $sync_result ) {
158 // Simple product or variation returns single ID
159 update_post_meta( $product_id, 'zcrm_product_sync_status', 'success' );
160 update_post_meta( $product_id, 'zcrm_product_sync_message', 'Product synced successfully to Zoho CRM with ID: ' . $sync_result );
161 } else {
162 update_post_meta( $product_id, 'zcrm_product_sync_status', 'failed' );
163 update_post_meta( $product_id, 'zcrm_product_sync_message', 'Failed to sync product to Zoho CRM' );
164 }
165 }
166 }
167 }
168
169 // if its variable product but without variations, then sync it.
170 $product = wc_get_product( $product_id );
171 if ( $product->is_type( 'variable' ) ) {
172 $variations = $product->get_available_variations();
173 if ( isset( $variations ) && count( $variations ) === 0 ) {
174 $zi_product_id = get_post_meta( $product_id, 'zi_item_id', true );
175 if ( ! empty( $zi_product_id ) ) {
176 $product_handler = new CMBIRD_Products_ZI();
177 $product_handler->import_variable_product_variations( $zi_product_id, $product_id );
178 }
179 }
180 }
181 }
182
183 /**
184 * Bulk-action to sync products from WooCommerce to Zoho
185 *
186 * @param: $bulk_array
187 * @return: $bulk_array
188 */
189 add_filter( 'bulk_actions-edit-product', 'cmbird_zi_sync_all_items_to_zoho' );
190 function cmbird_zi_sync_all_items_to_zoho( $bulk_array ) {
191 $bulk_array['sync_item_to_zoho'] = 'Sync to Zoho';
192 // add option to unmap items from zoho
193 $bulk_array['unmap_item_to_zoho'] = 'Unmap from Zoho';
194 return $bulk_array;
195 }
196
197 add_filter( 'handle_bulk_actions-edit-product', 'cmbird_zi_sync_all_items_to_zoho_handler', 10, 3 );
198 function cmbird_zi_sync_all_items_to_zoho_handler( $redirect, $action, $object_ids ) {
199 // let's remove query args first
200 $redirect = remove_query_arg( 'sync_item_to_zoho_done', $redirect );
201 $redirect = remove_query_arg( 'unmap_item_to_zoho_done', $redirect );
202
203 // do something for "Make Draft" bulk action
204 if ( 'sync_item_to_zoho' === $action ) {
205
206 foreach ( $object_ids as $post_id ) {
207 // Sync to Zoho Inventory
208 $product_handler = new CMBIRD_Products_ZI_Export();
209 $product_handler->cmbird_zi_product_sync( $post_id );
210
211 // Sync to Zoho CRM as well
212 $zoho_crm_access_token = get_option( 'cmbird_zoho_crm_access_token' );
213 if ( ! empty( $zoho_crm_access_token ) ) {
214 $cmbird_zcrm_product_sync = get_option( 'cmbird_zoho_crm_disable_product_sync_status' );
215 if ( ! $cmbird_zcrm_product_sync ) {
216 $product = wc_get_product( $post_id );
217 if ( $product ) {
218 $zcrm_product_handler = new CMBIRD_ZCRM_Product();
219 $zcrm_product_handler->cmbird_sync_product_to_zoho( $product );
220 }
221 }
222 }
223 }
224
225 // do not forget to add query args to URL because we will show notices later
226 $redirect = add_query_arg( 'sync_item_to_zoho_done', count( $object_ids ), $redirect );
227
228 } elseif ( 'unmap_item_to_zoho' === $action ) {
229 foreach ( $object_ids as $post_id ) {
230 $nonce = wp_create_nonce( 'zi_product_unmap_hook' );
231 cmbird_zi_product_unmap_hook( $post_id, $nonce );
232 }
233 // do not forget to add query args to URL because we will show notices later
234 $redirect = add_query_arg( 'unmap_item_to_zoho_done', count( $object_ids ), $redirect );
235 }
236
237 return $redirect;
238 }
239
240 // output the message of bulk action
241 add_action( 'admin_notices', 'cmbird_sync_item_to_zoho_notices' );
242 function cmbird_sync_item_to_zoho_notices() {
243 // verify nonce
244 if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-edit-products' ) ) {
245 return;
246 }
247 if ( ! empty( $_REQUEST['sync_item_to_zoho_done'] ) ) {
248 echo '<div id="message" class="updated notice is-dismissible">
249 <p>Products Synced. If product is not synced, please click on Edit Product to see the API response.</p>
250 </div>';
251 }
252 if ( ! empty( $_REQUEST['unmap_item_to_zoho_done'] ) ) {
253 echo '<div id="message" class="updated notice is-dismissible">
254 <p>Products Unmapped from Zoho.</p>
255 </div>';
256 }
257 }
258
259 /**
260 * Function to be called by ajax hook when unmap button called.
261 * This function remove zoho mapped id.
262 */
263 add_action( 'wp_ajax_zi_product_unmap_hook', 'cmbird_zi_product_unmap_hook' );
264 function cmbird_zi_product_unmap_hook( $product_id, $nonce = '' ) {
265 // if nonce is not there in the request, then check if it is passed as parameter
266 if ( ! $nonce ) {
267 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
268 }
269 // verify nonce
270 if ( ! $nonce || ! wp_verify_nonce( $nonce, 'zi_product_unmap_hook' ) ) {
271 wp_send_json_error( 'Nonce verification failed' );
272 }
273 if ( ! $product_id && isset( $_POST['product_id'] ) ) {
274 $product_id = sanitize_text_field( wp_unslash( $_POST['product_id'] ) );
275 }
276
277 if ( $product_id ) {
278 $product = wc_get_product( $product_id );
279 // If this is variable items then unmap all of it's variations.
280 if ( $product->is_type( 'variable' ) ) {
281 $variations = $product->get_available_variations();
282 if ( isset( $variations ) && count( $variations ) > 0 ) {
283 foreach ( $variations as $child ) {
284 delete_post_meta( $child['variation_id'], 'zi_item_id' );
285 delete_post_meta( $child['variation_id'], 'zi_account_id' );
286 delete_post_meta( $child['variation_id'], 'zi_account_name' );
287 delete_post_meta( $child['variation_id'], 'zi_category_id' );
288 delete_post_meta( $child['variation_id'], 'zi_inventory_account_id' );
289 delete_post_meta( $child['variation_id'], 'zi_purchase_account_id' );
290 }
291 }
292 }
293 delete_post_meta( $product_id, 'zi_item_id' );
294 delete_post_meta( $product_id, 'zi_account_id' );
295 delete_post_meta( $product_id, 'zi_account_name' );
296 delete_post_meta( $product_id, 'zi_category_id' );
297 delete_post_meta( $product_id, 'zi_inventory_account_id' );
298 delete_post_meta( $product_id, 'zi_purchase_account_id' );
299
300 // Also unmap from Zoho CRM
301 delete_post_meta( $product_id, 'zcrm_product_id' );
302 delete_post_meta( $product_id, 'zcrm_product_sync_status' );
303 delete_post_meta( $product_id, 'zcrm_product_sync_message' );
304
305 // update message
306 update_post_meta( $product_id, 'zi_product_errmsg', 'Product is Unmapped from Zoho Inventory and CRM' );
307 }
308 }
309
310 /**
311 * Function to be called by ajax hook when unmap button called.
312 * This function remove zoho mapped id.
313 */
314 add_action( 'wp_ajax_zi_customer_unmap_hook', 'cmbird_zi_customer_unmap_hook' );
315 function cmbird_zi_customer_unmap_hook( $order_id ) {
316 // verify Nonce
317 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'zi_customer_unmap_hook' ) ) {
318 wp_send_json_error( 'Nonce verification failed' );
319 }
320 if ( ! $order_id && isset( $_POST['order_id'] ) ) {
321 $order_id = sanitize_text_field( wp_unslash( $_POST['order_id'] ) );
322 }
323
324 $order = wc_get_order( $order_id );
325 $customer_id = $order->get_user_id();
326
327 if ( $customer_id ) {
328 delete_user_meta( $customer_id, 'zi_contact_id' );
329 delete_user_meta( $customer_id, 'zi_contact_persons_id' );
330 delete_user_meta( $customer_id, 'zi_contactperson_id_0' );
331 delete_user_meta( $customer_id, 'zi_contactperson_id_1' );
332 delete_user_meta( $customer_id, 'zi_currency_code' );
333 delete_user_meta( $customer_id, 'zi_currency_id' );
334 delete_user_meta( $customer_id, 'zi_created_time' );
335 delete_user_meta( $customer_id, 'zi_last_modified_time' );
336 delete_user_meta( $customer_id, 'zi_primary_contact_id' );
337 delete_user_meta( $customer_id, 'zi_billing_address_id' );
338 delete_user_meta( $customer_id, 'zi_shipping_address_id' );
339
340 $order->add_order_note( 'Zoho Sync: Customer is now unmapped. Please try syncing the order again' );
341 $order->save();
342 }
343 }
344
345 /**
346 * Add WordPress Meta box to show sync response
347 */
348 function cmbird_product_metabox() {
349 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
350 if ( ! $zoho_inventory_access_token ) {
351 return;
352 }
353 add_meta_box(
354 'zoho-product-sync',
355 __( 'Zoho Inventory', 'commercebird' ),
356 'cmbird_product_metabox_callback',
357 'product',
358 'side',
359 'high'
360 );
361 }
362 function cmbird_product_metabox_callback( $post ) {
363 $response = get_post_meta( $post->ID, 'zi_product_errmsg' );
364 echo 'API Response: ' . esc_html( implode( $response ) ) . '<br>';
365
366 // Show CRM sync status
367 $zcrm_sync_status = get_post_meta( $post->ID, 'zcrm_product_sync_status', true );
368 $zcrm_sync_message = get_post_meta( $post->ID, 'zcrm_product_sync_message', true );
369 if ( $zcrm_sync_status ) {
370 $status_color = 'success' === $zcrm_sync_status ? 'green' : 'red';
371 echo '<p style="color:' . esc_attr( $status_color ) . ';"><strong>CRM Sync:</strong> ' . esc_html( $zcrm_sync_message ) . '</p>';
372 }
373
374 // Generate nonce
375 $nonce = wp_create_nonce( 'zoho_admin_product_sync' );
376 $nonce_unmap = wp_create_nonce( 'zi_product_unmap_hook' );
377 $post_id = $post->ID;
378 echo '<br><a href="javascript:void(0)" style="width:100%; text-align: center;" class="button button-primary" onclick="zoho_admin_product_ajax(' . esc_attr( $post_id ) . ', \'' . esc_attr( $nonce ) . '\')">Sync Product</a>';
379 echo '<br><a href="javascript:void(0)" style="margin-top:10px; background:#b32d2e; border-color: #b32d2e; width:100%; text-align: center;" class="button button-primary" onclick="zoho_admin_unmap_product_ajax(' . esc_attr( $post_id ) . ', \'' . esc_attr( $nonce_unmap ) . '\')">Unmap this Product</a>';
380 $product = wc_get_product( $post->ID );
381 $product_type = $product->get_type();
382 if ( 'variable' === $product_type || 'variable-subscription' === $product_type ) {
383 echo '<p class="howto" style="color:#b32d2e;"><strong>Important : </strong> Please ensure all variations have price and SKU</p>';
384 }
385 // echo the zi_category_id
386 $zi_category_id = get_post_meta( $post->ID, 'zi_category_id', true );
387 if ( $zi_category_id ) {
388 echo '<p class="howto"><strong>Zoho Category: </strong>' . esc_html( $zi_category_id ) . '</p>';
389 }
390 // make api call to get the zoho item details
391 $zi_item_id = get_post_meta( $post->ID, 'zi_item_id', true );
392 if ( $zi_item_id && is_admin() ) {
393 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_organization_id' );
394 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
395 $urlitem = "{$zoho_inventory_url}inventory/v1/items/{$zi_item_id}?organization_id=$zoho_inventory_oid";
396 // fwrite( $fd, PHP_EOL . 'URL : ' . $urlitem );
397
398 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
399 $json = $execute_curl_call->execute_curl_call_get( $urlitem );
400 $code = (int) property_exists( $json, 'code' ) ? $json->code : '0';
401 if ( '0' === $code || 0 === $code ) {
402 // echo the item details here that are in array called "item"
403 $item = $json->item;
404 $actual_available_stock = (int) property_exists( $item, 'actual_available_stock' ) ? $item->actual_available_stock : '0';
405 $rate = (int) property_exists( $item, 'rate' ) ? $item->rate : '0';
406 echo '<p class="howto"><strong>Rate: </strong>' . esc_html( $rate ) . '</p>';
407 // echo the actual_available_stock
408 echo '<p class="howto"><strong>Available Stock: </strong>' . esc_html( $actual_available_stock ) . '</p>';
409 // echo the zoho category name from the item
410 $category_name = (string) property_exists( $item, 'category_name' ) ? $item->category_name : '';
411 if ( ! empty( $category_name ) || 'variable' === $product_type || 'variable-subscription' === $product_type ) {
412 echo '<p class="howto"><strong>Category Name: </strong>' . esc_html( $category_name ) . '</p>';
413 }
414 }
415 }
416 }
417 add_action( 'add_meta_boxes', 'cmbird_product_metabox' );
418
419
420 /**
421 * Add Zoho and Exact Item IDs to Product and Variations
422 * @return void
423 */
424 add_action( 'woocommerce_product_options_pricing', 'cmbird_item_id_field' );
425 add_action( 'woocommerce_variation_options_pricing', 'cmbird_item_id_variation_field', 10, 3 );
426 function cmbird_item_id_field() {
427 woocommerce_wp_text_input(
428 array(
429 'id' => '_cost_price',
430 'class' => 'readonly',
431 'wrapper_class' => 'form-row',
432 'label' => esc_html__( 'Cost Price', 'commercebird' ),
433 'data_type' => 'price',
434 'description' => esc_html__( 'You can edit this via the CommerceBird App', 'commercebird' ),
435 )
436 );
437 woocommerce_wp_text_input(
438 array(
439 'id' => 'eo_item_id',
440 'label' => esc_html__( 'Exact Item ID', 'commercebird' ),
441 'class' => 'readonly',
442 'desc_tip' => true,
443 'description' => esc_html__( 'This is the Exact Item ID of this product. You cannot change this', 'commercebird' ),
444 )
445 );
446 woocommerce_wp_text_input(
447 array(
448 'id' => 'zi_item_id',
449 'label' => esc_html__( 'Zoho Item ID', 'commercebird' ),
450 'class' => 'readonly',
451 'desc_tip' => true,
452 'description' => esc_html__( 'This is the Zoho Item ID of this product. You cannot change this', 'commercebird' ),
453 )
454 );
455 }
456 function cmbird_item_id_variation_field( $loop, $variation_data, $variation ) {
457 woocommerce_wp_text_input(
458 array(
459 'id' => 'cost_price[' . $loop . ']',
460 'class' => 'readonly',
461 'wrapper_class' => 'form-row',
462 'data_type' => 'price',
463 'label' => esc_html__( 'Cost Price', 'commercebird' ),
464 'value' => get_post_meta( $variation->ID, '_cost_price', true ),
465 'description' => esc_html__( 'You can edit this via the CommerceBird App', 'commercebird' ),
466 )
467 );
468 woocommerce_wp_text_input(
469 array(
470 'id' => 'eo_item_id[' . $loop . ']',
471 'class' => 'readonly',
472 'label' => esc_html__( 'Exact Item ID', 'commercebird' ),
473 'value' => get_post_meta( $variation->ID, 'eo_item_id', true ),
474 'desc_tip' => true,
475 'description' => esc_html__( 'This is the Exact Item ID of this product. You cannot change this', 'commercebird' ),
476 )
477 );
478 woocommerce_wp_text_input(
479 array(
480 'id' => 'zi_item_id[' . $loop . ']',
481 'class' => 'readonly',
482 'label' => esc_html__( 'Zoho Item ID', 'commercebird' ),
483 'value' => get_post_meta( $variation->ID, 'zi_item_id', true ),
484 'desc_tip' => true,
485 'description' => esc_html__( 'This is the Zoho Item ID of this product. You cannot change this', 'commercebird' ),
486 )
487 );
488 }
489
490 /**
491 * Adds 'Zoho Sync' column header to 'Orders' page immediately after 'Total' column.
492 *
493 * @param string[] $columns
494 * @return string[] $new_columns
495 */
496 function cmbird_zi_sync_column_orders_overview( $columns ) {
497 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
498 if ( empty( $zoho_inventory_access_token ) ) {
499 return $columns;
500 }
501 $new_columns = array();
502 foreach ( $columns as $column_name => $column_info ) {
503
504 $new_columns[ $column_name ] = $column_info;
505
506 if ( 'order_total' === $column_name ) {
507 $new_columns['zoho_sync'] = __( 'Zoho Sync', 'commercebird' );
508 }
509 }
510 return $new_columns;
511 }
512 add_filter( 'manage_woocommerce_page_wc-orders_columns', 'cmbird_zi_sync_column_orders_overview', 20 );
513
514 /**
515 * Adding Sync Status for Orders Column
516 *
517 * @param string $column Column name.
518 * @param int $order_id $order id.
519 * @return void
520 */
521 function cmbird_zi_add_zoho_orders_content( $column, $order_id ) {
522 $zi_url = get_option( 'cmbird_zoho_inventory_url' );
523 $zi_visit_url = str_replace( 'www.zohoapis', 'inventory.zoho', $zi_url );
524 switch ( $column ) {
525 case 'zoho_sync':
526 // Get custom order meta data.
527 $order = wc_get_order( $order_id );
528 $zi_order_id = $order->get_meta( 'zi_salesorder_id', true, 'edit' );
529 $url = $zi_visit_url . 'app#/salesorders/' . $zi_order_id;
530 if ( $zi_order_id ) {
531 echo '<span class="dashicons dashicons-yes-alt" style="color:green;"></span><a href="' . esc_url( $url ) . '" target="_blank"> <span class="dashicons dashicons-external" style="color:green;"></span> </a>';
532 } else {
533 echo '<span class="dashicons dashicons-dismiss" style="color:red;"></span>';
534 }
535 unset( $order );
536 break;
537 }
538 }
539 add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'cmbird_zi_add_zoho_orders_content', 20, 2 );
540
541 /**
542 * Adds 'Zoho Sync' column content.
543 *
544 * @param string[] $column name of column being displayed
545 */
546 function cmbird_zi_add_zoho_column_content( $column ) {
547 global $post;
548 $post_type = get_post_type( $post );
549
550 if ( 'zoho_sync' === $column && 'product' === $post_type ) {
551 $product_id = $post->ID;
552 $zi_product_id = get_post_meta( $product_id, 'zi_item_id' );
553 if ( $zi_product_id ) {
554 echo '<span class="dashicons dashicons-yes-alt" style="color:green;"></span>';
555 } else {
556 echo '<span class="dashicons dashicons-dismiss" style="color:red;"></span>';
557 }
558 }
559 }
560 add_action( 'manage_product_posts_custom_column', 'cmbird_zi_add_zoho_column_content' );
561
562 /**
563 * Adds 'Zoho Sync' column header to 'Products' page.
564 *
565 * @param string[] $columns
566 * @return string[] $new_columns
567 */
568 function cmbird_zi_sync_column_products_overview( $columns ) {
569 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
570 if ( empty( $zoho_inventory_access_token ) ) {
571 return $columns;
572 }
573 $new_columns = array();
574
575 foreach ( $columns as $column_name => $column_info ) {
576
577 $new_columns[ $column_name ] = $column_info;
578
579 if ( 'product_cat' === $column_name ) {
580 $new_columns['zoho_sync'] = __( 'Zoho Sync', 'commercebird' );
581 }
582 }
583
584 return $new_columns;
585 }
586 add_filter( 'manage_edit-product_columns', 'cmbird_zi_sync_column_products_overview', 20 );
587
588 /**
589 * Make 'Zoho Sync' column filterable.
590 */
591 function cmbird_zi_sync_column_filterable() {
592 global $typenow;
593
594 if ( 'product' === $typenow ) {
595 // code here
596 $value = isset( $_GET['zoho_sync_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['zoho_sync_filter'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
597
598 echo '<select name="zoho_sync_filter">';
599 echo '<option value="">Zoho Sync Filter</option>';
600
601 // Count synced products
602 $synced_count = new WP_Query(
603 array(
604 'post_type' => 'product',
605 'meta_query' => array(
606 array(
607 'key' => 'zi_item_id',
608 'compare' => 'EXISTS',
609 ),
610 ),
611 'fields' => 'ids',
612 )
613 );
614 $synced_count = $synced_count->found_posts;
615 $synced_label = 'Synced';
616 if ( $synced_count > 0 ) {
617 $synced_label .= ' (' . $synced_count . ')';
618 }
619 echo '<option value="synced" ' . selected( $value, 'synced', false ) . '>' . esc_html( $synced_label ) . '</option>';
620
621 // Count not synced products
622 $not_synced_count = new WP_Query(
623 array(
624 'post_type' => 'product',
625 'meta_query' => array(
626 array(
627 'key' => 'zi_item_id',
628 'compare' => 'NOT EXISTS',
629 ),
630 ),
631 'fields' => 'ids',
632 )
633 );
634 $not_synced_count = $not_synced_count->found_posts;
635 $not_synced_label = 'Not Synced';
636 if ( $not_synced_count > 0 ) {
637 $not_synced_label .= ' (' . $not_synced_count . ')';
638 }
639 echo '<option value="not_synced" ' . selected( $value, 'not_synced', false ) . '>' . esc_html( $not_synced_label ) . '</option>';
640
641 echo '</select>';
642 }
643 }
644 add_action( 'restrict_manage_posts', 'cmbird_zi_sync_column_filterable' );
645
646 /**
647 * Modify the product query based on the filter.
648 *
649 * @param WP_Query $query The query object.
650 */
651 function cmbird_zi_sync_column_filter_query( $query ) {
652 global $typenow, $pagenow;
653
654 if ( $typenow === 'product' && $pagenow === 'edit.php' && isset( $_GET['zoho_sync_filter'] ) && $_GET['zoho_sync_filter'] !== '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
655 $value = sanitize_text_field( wp_unslash( $_GET['zoho_sync_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
656
657 $meta_query = array();
658
659 if ( $value === 'synced' ) {
660 $meta_query[] = array(
661 'key' => 'zi_item_id',
662 'compare' => 'EXISTS',
663 );
664 } elseif ( $value === 'not_synced' ) {
665 $meta_query[] = array(
666 'relation' => 'OR',
667 array(
668 'key' => 'zi_item_id',
669 'compare' => 'NOT EXISTS',
670 ),
671 array(
672 'key' => 'zi_item_id',
673 'value' => '',
674 'compare' => '=',
675 ),
676 );
677 }
678
679 $query->set( 'meta_query', $meta_query );
680 }
681 }
682 add_action( 'pre_get_posts', 'cmbird_zi_sync_column_filter_query' );
683
684 /**
685 * Change Action Scheduler default purge to 1 week
686 * @return int
687 */
688 function cmbird_action_scheduler_purge() {
689 return WEEK_IN_SECONDS;
690 }
691 add_filter( 'action_scheduler_retention_period', 'cmbird_action_scheduler_purge' );
692
693 add_filter(
694 'action_scheduler_default_cleaner_statuses',
695 function ($statuses) {
696 $statuses[] = ActionScheduler_Store::STATUS_FAILED;
697 return $statuses;
698 }
699 );
700
701 /**
702 * Modify the Products API to include brands.
703 *
704 * TODO: This is a temporary solution. We need to find a better way to include brands in the API response.
705 *
706 * @param $response The response object.
707 * @param $post The post object.
708 * @param $request The request object.
709 * @return mixed
710 */
711 //add_filter( 'woocommerce_rest_prepare_product_object', 'cmbird_rest_api_prepare_brands_tax', 10, 3 );
712 function cmbird_rest_api_prepare_brands_tax( $response, $object, $request ) {
713 $product_id = $object->get_id();
714 if ( empty( $response->data['product_brands'] ) ) {
715 $terms = [];
716 foreach ( wp_get_post_terms( $product_id, 'product_brands' ) as $term ) {
717 $terms[] = [
718 'id' => $term->term_id,
719 'name' => $term->name,
720 'slug' => $term->slug,
721 ];
722 }
723 $response->data['product_brands'] = $terms;
724 }
725 return $response;
726 }
727
728
729 function cmbird_prepare_insert_product( $product, $request ) {
730 if ( isset( $request['product_brands'] ) ) {
731 wp_set_post_terms( $request['id'], $request['product_brands'], 'product_brands', false );
732 }
733 return $product;
734 }
735 // add_filter( 'woocommerce_rest_pre_insert_product_object', 'cmbird_prepare_insert_product', 10, 2 );