PluginProbe
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 3.1.0
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v3.1.0
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
395 lines 13.4 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.1.0
8 * Requires PHP: 8.2
9 * Requires Plugins: woocommerce
10 * Requires at least: 7.0
11 * Tested up to: 7.1
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.1.0' );
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 // Ensure @wordpress/interactivity module is loaded on every page.
264 add_action(
265 'wp_enqueue_scripts',
266 function () {
267 if ( ! function_exists( 'wp_register_script_module' ) ) {
268 return;
269 }
270 // Register the interactivity runtime if not already registered.
271 wp_register_script_module(
272 '@wordpress/interactivity',
273 includes_url( 'js/dist/script-modules/interactivity/index.min.js' ),
274 array(),
275 get_bloginfo( 'version' )
276 );
277 wp_enqueue_script_module( '@wordpress/interactivity' );
278
279 // Enqueue the search modal view module on every page.
280 wp_enqueue_script_module(
281 'commercebird-search-modal-view',
282 CMBIRD_URL . 'includes/classes/blocks/search-modal/view.js',
283 array( '@wordpress/interactivity' ),
284 CMBIRD_VERSION
285 );
286 }
287 );
288
289 add_action(
290 'enqueue_block_editor_assets',
291 function () {
292 wp_enqueue_script(
293 'commercebird-search-modal-editor',
294 CMBIRD_URL . 'includes/classes/blocks/search-modal/editor.js',
295 array( 'wp-blocks', 'wp-element' ),
296 CMBIRD_VERSION,
297 true
298 );
299 }
300 );
301
302 add_action(
303 'save_post',
304 function ( $post_id, $post ) {
305 if ( 'wcb2b_group' === $post->post_type ) {
306 delete_option( 'cmbird_wcb2b_groups' );
307 }
308 },
309 10,
310 2
311 );
312
313 /**
314 * Perform actions when the plugin is updated
315 *
316 * @param string $upgrader_object
317 * @param array $options
318 * @return void
319 */
320 add_action( 'upgrader_process_complete', 'cmbird_update_plugin_tasks', 10, 2 );
321
322 /**
323 * Perform tasks when the plugin is updated.
324 *
325 * @param \WP_Upgrader $upgrader_object - Upgrader object.
326 * @param array $options - Options array.
327 *
328 * @see https://developer.wordpress.org/reference/hooks/upgrader_process_complete/
329 */
330 function cmbird_update_plugin_tasks( $upgrader_object, $options ) {
331 $this_plugin = plugin_basename( __FILE__ );
332
333 if ( ! is_array( $options ) ) {
334 return;
335 }
336
337 if ( ! isset( $options['action'], $options['type'], $options['plugins'] ) || ! is_array( $options['plugins'] ) ) {
338 return;
339 }
340
341 if ( 'update' === $options['action'] && 'plugin' === $options['type'] ) {
342 foreach ( $options['plugins'] as $plugin ) {
343 if ( $plugin === $this_plugin ) {
344 // Ensure category mapping table exists before any table-backed migrations run.
345 Plugin::ensure_zi_category_map_table();
346
347 // Perform tasks when the plugin is updated.
348 // Updating meta key from '_cost_price' to '_cogs_total_value'.
349 global $wpdb;
350 $wpdb->query(
351 $wpdb->prepare(
352 "UPDATE {$wpdb->postmeta} SET meta_key = %s WHERE meta_key = %s",
353 '_cogs_total_value',
354 '_cost_price'
355 )
356 );
357 // Enable MCP WooCommerce integration. Remove this when enabled in Woo core.
358 update_option( 'woocommerce_feature_mcp_integration_enabled', 'yes' );
359 update_option( 'woocommerce_feature_cost_of_goods_sold_enabled', 'yes' );
360 update_option( 'woocommerce_feature_fulfillments_enabled', 'no' );
361 // One-time cleanup for old per-minute Zoho API rate limit counters.
362 $wpdb->query(
363 $wpdb->prepare(
364 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
365 $wpdb->esc_like( 'cmbird_zoho_api_calls_' ) . '%'
366 )
367 );
368 break;
369 }
370 }
371 }
372
373 // One-shot migration of legacy category mapping options into the new table.
374 if ( ! get_option( 'cmbird_zi_category_map_migrated' ) ) {
375 $report = \CommerceBird\Admin\Mappings\ZohoCategoryMap::migrate_legacy_options();
376
377 if ( ! empty( $report['skipped'] ) ) {
378 set_transient( 'cmbird_zi_category_map_migration_report', $report['skipped'], DAY_IN_SECONDS );
379 }
380
381 update_option( 'cmbird_zi_category_map_migrated', '1', false );
382 }
383 }
384
385 /**
386 * Instantiate the MCP adapter. Remove this when its included in Woo core.
387 */
388 // 1. Check if MCP Adapter is available
389 if ( ! class_exists( McpAdapter::class ) ) {
390 // Handle missing dependency (show admin notice, etc.).
391 return;
392 }
393 // 2. Initialize the adapter
394 McpAdapter::instance();
395