PluginProbe
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 3.0.6
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v3.0.6
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 All 65 releases
commercebird / commercebird.php

commercebird.php in CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). 3.0.6, at commercebird.php

406 lines 13.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: CommerceBird
4 * Plugin URI: https://commercebird.com
5 * Author: CommerceBird
6 * Description: This plugin helps you get the most of CommerceBird AI App and use integrations like Zoho Inventory, Zoho CRM, Exact Online and more. Requires a subscription at CommerceBird.com.
7 * Version: 3.0.6
8 * Requires PHP: 8.2
9 * Requires Plugins: woocommerce
10 * Requires at least: 7.0
11 * Tested up to: 7.0
12 * Text Domain: commercebird
13 * Domain Path: /languages
14 *
15 * License: GNU General Public License v3.0
16 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
17 *
18 * @category Fulfillment
19 * @package CommerceBird
20 * @author Fawad Tiemoerie <info@commercebird.com>
21 * @copyright Copyright (c) 2026, CommerceBird
22 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL-3.0-or-later
23 *
24 * WC requires at least: 10.7.0
25 * WC tested up to: 11.0.1
26 */
27
28 if ( ! defined( 'ABSPATH' ) ) {
29 exit; // Exit if accessed directly.
30 }
31
32 if ( ! defined( 'CMBIRD_VERSION' ) ) {
33 define( 'CMBIRD_VERSION', '3.0.6' );
34 }
35 if ( ! defined( 'CMBIRD_ZI_CATEGORY_MAP_LEGACY_FALLBACK' ) ) {
36 define( 'CMBIRD_ZI_CATEGORY_MAP_LEGACY_FALLBACK', true );
37 }
38 if ( ! defined( 'CMBIRD_PATH' ) ) {
39 define( 'CMBIRD_PATH', plugin_dir_path( __FILE__ ) );
40 }
41 if ( ! defined( 'CMBIRD_URL' ) ) {
42 define( 'CMBIRD_URL', plugin_dir_url( __FILE__ ) );
43 }
44 if ( ! defined( 'CMBIRD_MENU_SLUG' ) ) {
45 define( 'CMBIRD_MENU_SLUG', 'commercebird-app' );
46 }
47
48 require_once CMBIRD_PATH . 'includes/woo-functions.php';
49 require_once CMBIRD_PATH . 'includes/sync/order-backend.php';
50
51 // Load the Jetpack autoloader instead of vendor/autoload.php.
52 require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload_packages.php';
53
54 use Automattic\WooCommerce\Utilities\FeaturesUtil;
55 use WP\MCP\Core\McpAdapter;
56 use CommerceBird\Admin\Actions\Sync\ExactOnlineSync;
57 use CommerceBird\Admin\Actions\Ajax\ExactOnlineAjax;
58 use CommerceBird\Admin\Actions\Ajax\ZohoInventoryAjax;
59 use CommerceBird\Admin\Actions\Sync\ZohoCRMSync;
60 use CommerceBird\API\CMBird_APIs;
61 use CommerceBird\API\CreateOrderWebhook;
62 use CommerceBird\API\Exact;
63 use CommerceBird\API\Invoices;
64 use CommerceBird\API\ProductWebhook;
65 use CommerceBird\API\ShippingWebhook;
66 use CommerceBird\API\Zoho;
67 use CommerceBird\CMBIRD_MCP;
68 use CommerceBird\Plugin;
69
70 /*
71 |--------------------------------------------------------------------------
72 | Activation, deactivation and uninstall event.
73 |--------------------------------------------------------------------------
74 */
75
76 register_activation_hook( __FILE__, array( Plugin::class, 'activate' ) );
77 register_deactivation_hook( __FILE__, array( Plugin::class, 'deactivate' ) );
78 register_uninstall_hook( __FILE__, array( Plugin::class, 'uninstall' ) );
79
80 /*
81 |--------------------------------------------------------------------------
82 | Load the plugin translations
83 |--------------------------------------------------------------------------
84 | Note: WordPress.org automatically loads translations for plugins since WP 4.6.
85 | Manual loading not required for plugins hosted on WordPress.org.
86 */
87
88 /** Loading Purchase Order Class
89 *
90 * @since 1.0.0
91 */
92 function cmbird_purchase_order_class() {
93 if ( class_exists( 'WooCommerce' ) ) {
94 new CMBIRD_Purchase_Order();
95 }
96 }
97 add_action( 'woocommerce_init', 'cmbird_purchase_order_class' );
98 add_action( 'init', array( CMBIRD_PO_Admin_Manager::class, 'init' ), 11 );
99
100 /*
101 |--------------------------------------------------------------------------
102 | Start the plugin
103 |--------------------------------------------------------------------------
104 */
105 Plugin::init();
106
107 /**
108 * Declaring compatibility for WooCommerce HPOS
109 */
110 add_action(
111 'before_woocommerce_init',
112 function () {
113 if ( class_exists( FeaturesUtil::class ) ) {
114 FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
115 FeaturesUtil::declare_compatibility( 'product_instance_caching', __FILE__, true );
116 }
117 }
118 );
119
120 /*
121 --------------------------------------------------------------------------
122 | Install required dependencies
123 |--------------------------------------------------------------------------
124 */
125 add_action(
126 'plugins_loaded',
127 static function () {
128 // Initialize Quotes module.
129 CMBIRD_Quotes::init();
130 // Initialize MCP abilities.
131 CMBIRD_MCP::init();
132 // Only if plan is active via transient subscription_details.
133 $subscription = get_transient( 'subscription_details' );
134 // return if no subscription found.
135 if ( empty( $subscription ) ) {
136 return;
137 } else {
138 WP_Dependency_Installer::instance( __DIR__ )->run();
139 }
140 }
141 );
142
143 /**
144 * Hooks for WC Action Scheduler to import or export products
145 */
146 $cmbird_import_products = new CMBIRD_Products_ZI();
147 $cmbird_import_pricelist = new CMBIRD_Pricelist_ZI();
148 $cmbird_product_class = new CMBIRD_Products_ZI_Export();
149 $cmbird_common_class = new CMBIRD_Common_Functions();
150 $cmbird_contact_class = new CMBIRD_Contact_ZI();
151 $cmbird_category_class = new CMBIRD_Categories_ZI();
152 $cmbird_import_pricelist->wc_b2b_groups();
153 add_action( 'import_group_items_cron', array( $cmbird_import_products, 'sync_groupitem_recursively' ), 10, 2 );
154 add_action( 'import_simple_items_cron', array( $cmbird_import_products, 'sync_items_batch' ), 10, 2 );
155 add_action( 'import_variable_product_cron', array( $cmbird_import_products, 'import_variable_product_variations' ), 10, 2 );
156 add_action( 'sync_zi_product_cron', array( $cmbird_product_class, 'cmbird_zi_products_prepare_sync' ), 10, 2 );
157 add_action( 'sync_zi_pricelist', array( $cmbird_import_pricelist, 'zi_get_pricelist' ), 10, 2 );
158 add_action( 'cmbird_pricelist_addify_page', array( $cmbird_import_pricelist, 'process_addify_page' ), 10, 3 );
159 add_action( 'cmbird_pricelist_wc_b2b_page', array( $cmbird_import_pricelist, 'process_wc_b2b_page' ), 10, 3 );
160 add_action( 'sync_zi_order', array( $cmbird_common_class, 'cmbird_orders_prepare_sync' ), 10, 2 );
161 add_action( 'sync_zi_import_contacts', array( $cmbird_contact_class, 'cmbird_get_zoho_contacts' ), 10, 2 );
162 add_action( 'cmbird_zi_salesorder_cron_daily', array( ZohoInventoryAjax::instance(), 'salesorder_cron_fetch' ) );
163 add_action( 'cmbird_zi_import_salesorder_from_cron', array( ZohoInventoryAjax::instance(), 'import_salesorder_from_cron' ), 10, 1 );
164 // Cascade Zoho category mapping deletion when a WC product category is deleted.
165 add_action(
166 'delete_term',
167 static function ( $term_id, $tt_id, $taxonomy ) {
168 if ( 'product_cat' !== $taxonomy ) {
169 return;
170 }
171 ( new \CommerceBird\Admin\Mappings\ZohoCategoryMap() )->forget_term( (int) $term_id );
172 },
173 10,
174 3
175 );
176 // add action to set the zoho rate limit option exceeded to false.
177 add_action( 'cmbird_common', array( CMBIRD_Common_Functions::class, 'set_zoho_rate_limit_option' ) );
178 // Zoho CRM Hooks.
179 add_action( 'sync_zcrm_order', array( $cmbird_common_class, 'cmbird_orders_prepare_sync' ) );
180 add_action( 'sync_zcrm_contact', array( ZohoCRMSync::class, 'cmbird_zcrm_contact_sync' ) );
181 // Exact Online Hooks.
182 $exact_online_sync = new ExactOnlineSync();
183 add_action( 'cmbird_sync_eo', array( $exact_online_sync, 'sync' ), 10, 3 );
184 add_action( 'cmbird_exact_online_sync_orders', array( ExactOnlineSync::class, 'sync_orders_via_cron' ) );
185 add_action( 'cmbird_payment_status', array( ExactOnlineSync::class, 'cmbird_payment_status' ), 10, 1 );
186 add_action( 'cmbird_eo_get_payment_statuses', array( ExactOnlineSync::class, 'get_payment_status_via_cron' ) );
187 add_filter( 'cron_schedules', array( ExactOnlineAjax::instance(), 'register_product_cron_schedules' ) );
188 add_action( 'cmbird_eo_product_mapping_daily', array( ExactOnlineAjax::instance(), 'product_map_cron' ) );
189 add_action( 'cmbird_eo_product_daily_reset', array( ExactOnlineAjax::instance(), 'product_map_daily_reset' ) );
190 // Callback functions for scheduled action to process product or customer chunk.
191 add_action(
192 'cmbird_process_product_chunk',
193 function ( $args ) {
194 if ( ! is_array( $args ) || empty( $args['transient_key'] ) ) {
195 return;
196 }
197 $transient_key = $args['transient_key'];
198 $import_products = $args['import_products'] ?? false;
199 $chunked_products = get_transient( $transient_key );
200 if ( $chunked_products ) {
201 $sync = new ExactOnlineSync();
202 $sync->sync( 'product', $chunked_products, (bool) $import_products );
203 // Remove transient after processing.
204 delete_transient( $transient_key );
205 }
206 },
207 10,
208 1
209 );
210 add_action(
211 'cmbird_process_customer_chunk',
212 function ( $args ) {
213 if ( ! is_array( $args ) || empty( $args['transient_key'] ) ) {
214 return;
215 }
216 $transient_key = $args['transient_key'];
217 $import_customers = $args['import_customers'] ?? false;
218 $chunked_customers = get_transient( $transient_key );
219 if ( $chunked_customers ) {
220 $sync = new ExactOnlineSync();
221 $sync->sync( 'customer', $chunked_customers, (bool) $import_customers );
222 // Remove transient after processing.
223 delete_transient( $transient_key );
224 }
225 },
226 10,
227 1
228 );
229 // Zoho CRM Hooks.
230 add_action( 'init', array( ZohoCRMSync::class, 'refresh_token' ) );
231 // Zoho Inventory Cron Hook for importing items.
232 add_action( 'zi_execute_import_sync', array( Plugin::class, 'dispatch_import_simple_items' ) );
233
234 // add classes to REST API.
235 add_action(
236 'rest_api_init',
237 function () {
238 new Zoho();
239 new Exact();
240 new ProductWebhook();
241 new ShippingWebhook();
242 new CreateOrderWebhook();
243 new CMBird_APIs();
244 // Invoices is only declared when PDF Invoices Pro is NOT providing its own
245 // REST layer (see the guard in class-api-for-invoices.php). On a Pro site
246 // WPO_WCPDF still exists, so the class has to be checked as well.
247 if ( class_exists( 'WPO_WCPDF' ) && class_exists( Invoices::class ) ) {
248 new Invoices();
249 }
250 $po_controller = new CMBIRD_REST_Shop_Purchase_Controller();
251 $po_controller->register_routes();
252 }
253 );
254
255 // Register CommerceBird blocks.
256 add_action(
257 'init',
258 function () {
259 register_block_type( CMBIRD_PATH . 'includes/classes/blocks/search-modal/block.json' );
260 }
261 );
262
263 // Always render the search modal in the footer so it works on every page.
264 add_action(
265 'wp_footer',
266 function () {
267 $render = CMBIRD_PATH . 'includes/classes/blocks/search-modal/render.php';
268 if ( file_exists( $render ) ) {
269 require $render;
270 }
271 }
272 );
273
274 // Ensure @wordpress/interactivity module is loaded on every page.
275 add_action(
276 'wp_enqueue_scripts',
277 function () {
278 if ( ! function_exists( 'wp_register_script_module' ) ) {
279 return;
280 }
281 // Register the interactivity runtime if not already registered.
282 wp_register_script_module(
283 '@wordpress/interactivity',
284 includes_url( 'js/dist/script-modules/interactivity/index.min.js' ),
285 array(),
286 get_bloginfo( 'version' )
287 );
288 wp_enqueue_script_module( '@wordpress/interactivity' );
289
290 // Enqueue the search modal view module on every page.
291 wp_enqueue_script_module(
292 'commercebird-search-modal-view',
293 CMBIRD_URL . 'includes/classes/blocks/search-modal/view.js',
294 array( '@wordpress/interactivity' ),
295 CMBIRD_VERSION
296 );
297 }
298 );
299
300 add_action(
301 'enqueue_block_editor_assets',
302 function () {
303 wp_enqueue_script(
304 'commercebird-search-modal-editor',
305 CMBIRD_URL . 'includes/classes/blocks/search-modal/editor.js',
306 array( 'wp-blocks', 'wp-element' ),
307 CMBIRD_VERSION,
308 true
309 );
310 }
311 );
312
313 add_action(
314 'save_post',
315 function ( $post_id, $post ) {
316 if ( 'wcb2b_group' === $post->post_type ) {
317 delete_option( 'cmbird_wcb2b_groups' );
318 }
319 },
320 10,
321 2
322 );
323
324 /**
325 * Perform actions when the plugin is updated
326 *
327 * @param string $upgrader_object
328 * @param array $options
329 * @return void
330 */
331 add_action( 'upgrader_process_complete', 'cmbird_update_plugin_tasks', 10, 2 );
332
333 /**
334 * Perform tasks when the plugin is updated.
335 *
336 * @param \WP_Upgrader $upgrader_object - Upgrader object.
337 * @param array $options - Options array.
338 *
339 * @see https://developer.wordpress.org/reference/hooks/upgrader_process_complete/
340 */
341 function cmbird_update_plugin_tasks( $upgrader_object, $options ) {
342 $this_plugin = plugin_basename( __FILE__ );
343
344 if ( ! is_array( $options ) ) {
345 return;
346 }
347
348 if ( ! isset( $options['action'], $options['type'], $options['plugins'] ) || ! is_array( $options['plugins'] ) ) {
349 return;
350 }
351
352 if ( 'update' === $options['action'] && 'plugin' === $options['type'] ) {
353 foreach ( $options['plugins'] as $plugin ) {
354 if ( $plugin === $this_plugin ) {
355 // Ensure category mapping table exists before any table-backed migrations run.
356 Plugin::ensure_zi_category_map_table();
357
358 // Perform tasks when the plugin is updated.
359 // Updating meta key from '_cost_price' to '_cogs_total_value'.
360 global $wpdb;
361 $wpdb->query(
362 $wpdb->prepare(
363 "UPDATE {$wpdb->postmeta} SET meta_key = %s WHERE meta_key = %s",
364 '_cogs_total_value',
365 '_cost_price'
366 )
367 );
368 // Enable MCP WooCommerce integration. Remove this when enabled in Woo core.
369 update_option( 'woocommerce_feature_mcp_integration_enabled', 'yes' );
370 update_option( 'woocommerce_feature_cost_of_goods_sold_enabled', 'yes' );
371 update_option( 'woocommerce_feature_fulfillments_enabled', 'no' );
372 // One-time cleanup for old per-minute Zoho API rate limit counters.
373 $wpdb->query(
374 $wpdb->prepare(
375 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
376 $wpdb->esc_like( 'cmbird_zoho_api_calls_' ) . '%'
377 )
378 );
379 break;
380 }
381 }
382 }
383
384 // One-shot migration of legacy category mapping options into the new table.
385 if ( ! get_option( 'cmbird_zi_category_map_migrated' ) ) {
386 $report = \CommerceBird\Admin\Mappings\ZohoCategoryMap::migrate_legacy_options();
387
388 if ( ! empty( $report['skipped'] ) ) {
389 set_transient( 'cmbird_zi_category_map_migration_report', $report['skipped'], DAY_IN_SECONDS );
390 }
391
392 update_option( 'cmbird_zi_category_map_migrated', '1', false );
393 }
394 }
395
396 /**
397 * Instantiate the MCP adapter. Remove this when its included in Woo core.
398 */
399 // 1. Check if MCP Adapter is available
400 if ( ! class_exists( McpAdapter::class ) ) {
401 // Handle missing dependency (show admin notice, etc.).
402 return;
403 }
404 // 2. Initialize the adapter
405 McpAdapter::instance();
406