PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 3.0.3
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v3.0.3
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 / classes / class-plugin.php
commercebird / includes / classes Last commit date
ai 3 weeks ago apis 5 days ago purchase-orders 5 days ago quotes 1 month ago zoho-crm 6 months ago zoho-inventory 5 days ago class-api-handler-zoho.php 5 days ago class-auth-zoho.php 3 months ago class-common.php 1 month ago class-mcp.php 5 days ago class-plugin.php 2 weeks ago class-wc-api.php 5 months ago index.php 1 year ago
class-plugin.php
350 lines
1 <?php
2
3 namespace CommerceBird;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
10
11 use CommerceBird\Admin\Actions\Ajax\ExactOnlineAjax;
12 use CommerceBird\Admin\Actions\Ajax\ZohoInventoryAjax;
13 use CommerceBird\Admin\Actions\Ajax\ZohoCRMAjax;
14 use CommerceBird\Admin\Actions\Ajax\AcfAjax;
15 use CommerceBird\Admin\Actions\Ajax\SettingsAjax;
16 use CommerceBird\Admin\Template;
17 use CommerceBird\Admin\Cmbird_Acf;
18 use CommerceBird\CMBIRD_AI_Product_Blocks_Block;
19 use CommerceBird\CMBIRD_AI_Product_Blocks_Cron;
20 use CommerceBird\CMBIRD_AI_Product_Blocks_Display;
21 use CommerceBird\Cmbird_WC_API;
22 use CMBIRD_Purchase_Orders_Automation;
23
24 /**
25 * Main plugin class for CommerceBird.
26 *
27 * Handles activation, deactivation, uninstall, and initialization logic.
28 *
29 * @since 1.0.0
30 */
31 class Plugin {
32
33
34 /**
35 * The constructor for the plugin.
36 *
37 * @since 1.0.0
38 *
39 * This function is called when the plugin is loaded. It hooks the init method to the admin_init action.
40 */
41 public function __construct() {
42 add_action( 'admin_init', array( $this, 'init' ) );
43 }
44
45 /**
46 * Plugin activation handler.
47 *
48 * - Installs the MU CLI helper.
49 * - Ensures the "vendor" role exists.
50 * - Creates {$wpdb->prefix}cmbird_zi_category_map via dbDelta (idempotent).
51 *
52 * @since 1.0.0
53 */
54 public static function activate() {
55 // Copy CLI script to mu-plugins folder for automatic loading.
56 self::install_mu_plugin();
57 CMBIRD_AI_Product_Blocks_Cron::activate();
58 // Create the "vendor" role — must run at activation, not on every init.
59 if ( ! get_role( 'vendor' ) ) {
60 add_role(
61 'vendor',
62 __( 'Vendor', 'commercebird' ),
63 array( 'read' => true )
64 );
65 }
66
67 self::ensure_zi_category_map_table();
68 }
69
70 /**
71 * Ensure the Zoho category mapping table exists.
72 *
73 * Uses dbDelta so it is safe to call repeatedly on activation and upgrades.
74 *
75 * @since 2.9.2
76 * @return void
77 */
78 public static function ensure_zi_category_map_table() {
79 global $wpdb;
80 $charset_collate = $wpdb->get_charset_collate();
81 $table = $wpdb->prefix . 'cmbird_zi_category_map';
82 $sql = "CREATE TABLE {$table} (
83 id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
84 wc_term_id BIGINT UNSIGNED NOT NULL,
85 zoho_category_id VARCHAR(64) NOT NULL,
86 source ENUM('auto','manual') NOT NULL DEFAULT 'auto',
87 status ENUM('active','orphan','review') NOT NULL DEFAULT 'active',
88 review_reason VARCHAR(64) NULL,
89 created_at DATETIME NOT NULL,
90 updated_at DATETIME NOT NULL,
91 last_verified_at DATETIME NULL,
92 PRIMARY KEY (id),
93 UNIQUE KEY uniq_wc_term_active (wc_term_id, status),
94 UNIQUE KEY uniq_zoho_id_active (zoho_category_id, status),
95 KEY status_idx (status)
96 ) $charset_collate;";
97 dbDelta( $sql );
98 }
99
100 /**
101 * Copy the CLI script to mu-plugins folder.
102 *
103 * @since 2.6.5
104 */
105 private static function install_mu_plugin() {
106 $mu_plugins_dir = WP_CONTENT_DIR . '/mu-plugins';
107 $source_file = CMBIRD_PATH . 'mu-plugins/cmbird-media-cleanup-cli.php';
108 $dest_file = $mu_plugins_dir . '/cmbird-media-cleanup-cli.php';
109
110 // Create mu-plugins directory if it doesn't exist.
111 if ( ! is_dir( $mu_plugins_dir ) ) {
112 wp_mkdir_p( $mu_plugins_dir );
113 }
114
115 // Copy the file if source exists and destination doesn't or is outdated.
116 if ( file_exists( $source_file ) ) {
117 if ( ! file_exists( $dest_file ) || filemtime( $source_file ) > filemtime( $dest_file ) ) {
118 copy( $source_file, $dest_file );
119 }
120 }
121 }
122
123 /**
124 * Clear all the scheduled actions when the plugin is deactivated.
125 *
126 * @since 1.0.0
127 */
128 public static function deactivate() {
129 CMBIRD_AI_Product_Blocks_Cron::deactivate();
130 wp_clear_scheduled_hook( 'zi_execute_import_sync' );
131 wp_clear_scheduled_hook( 'cmbird_eo_get_payment_statuses' );
132 wp_clear_scheduled_hook( 'cmbird_exact_online_sync_orders' );
133 wp_clear_scheduled_hook( 'cmbird_eo_product_mapping_daily' );
134 wp_clear_scheduled_hook( 'cmbird_zoho_sync_category_cron' );
135 wp_clear_scheduled_hook( 'cmbird_zoho_contact_sync' );
136 }
137
138 /**
139 * Deletes all the options and post/user meta set by the plugin.
140 *
141 * This function is called when the plugin is uninstalled.
142 *
143 * @since 1.0.0
144 */
145 public static function uninstall() {
146 $post_meta_keys = array(
147 'zi_item_id',
148 'zi_purchase_account_id',
149 'zi_account_id',
150 'zi_account_name',
151 'zi_inventory_account_id',
152 'zi_salesorder_id',
153 'zi_category_id',
154 '_cost_price',
155 'eo_item_id',
156 );
157 $user_meta_keys = array(
158 'zi_contact_id',
159 'zi_primary_contact_id',
160 'zi_created_time',
161 'zi_last_modified_time',
162 'zi_billing_address_id',
163 'zi_shipping_address_id',
164 'zi_contact_persons_id',
165 'zi_currency_id',
166 'zi_currency_code',
167 'eo_contact_id',
168 'eo_account_id',
169 'eo_gl_account',
170 );
171 $zi_option_keys = array(
172 'cmbird_zi_webhook_password',
173 'cmbird_zoho_inventory_cron_class',
174 'cmbird_zoho_sync_status',
175 'cmbird_zoho_item_category',
176 'cmbird_zoho_stock_sync_status',
177 'cmbird_zoho_item_name_sync_status',
178 'cmbird_zoho_enable_auto_no_status',
179 'cmbird_zoho_product_sync_status',
180 'cmbird_zoho_disable_image_sync_status',
181 'cmbird_zoho_disable_price_sync_status',
182 'cmbird_zoho_disable_name_sync_status',
183 'cmbird_zoho_disable_description_sync_status',
184 'cmbird_zoho_enable_accounting_stock_status',
185 'cmbird_zoho_enable_order_status',
186 'cmbird_wootozoho_custom_fields',
187 'cmbird_zoho_pricelist_id',
188 'cmbird_zoho_location_id_status',
189 'cmbird_zoho_inventory_auth_code',
190 'cmbird_zoho_inventory_access_token',
191 'cmbird_zoho_inventory_refresh_token',
192 'cmbird_zoho_inventory_timestamp',
193 'cmbird_zoho_inventory_oid',
194 'cmbird_zoho_inventory_url',
195 'cmbird_zoho_inventory_cid',
196 'cmbird_zoho_inventory_cs',
197 'cmbird_zoho_inventory_domain',
198 'cmbird_authorization_redirect_uri',
199 'cmbird_zoho_crm_auth_code',
200 'cmbird_zoho_crm_access_token',
201 'cmbird_zoho_crm_refresh_token',
202 'cmbird_zoho_crm_timestamp',
203 'cmbird_location_data',
204 'cmbird_ai_review_summary_enabled',
205 'cmbird_ai_review_summary_prompt',
206 'cmbird_ai_content_writer_enabled',
207 'cmbird_ai_shopping_experience_enabled',
208 'cmbird_eo_product_cron_enabled',
209 );
210
211 foreach ( $zi_option_keys as $zi_option ) {
212 delete_option( $zi_option );
213 }
214
215 foreach ( $post_meta_keys as $post_key ) {
216 delete_post_meta_by_key( $post_key );
217 }
218
219 $users = get_users(
220 array(
221 'fields' => array( 'ID' ),
222 )
223 );
224 foreach ( $users as $user_id ) {
225 foreach ( $user_meta_keys as $user_key ) {
226 delete_user_meta( $user_id, $user_key );
227 }
228 }
229 // Drop the category mapping table.
230 global $wpdb;
231 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}cmbird_zi_category_map" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
232
233 // Clean up any legacy mapping options (covers installs that never ran the migration).
234 $wpdb->query(
235 "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'cmbird_zoho_id_for_term_id_%'" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
236 );
237
238 // And the migration flags.
239 delete_option( 'cmbird_zi_category_map_migrated' );
240 delete_option( 'cmbird_zi_category_map_legacy_purged' );
241 // clear scheduled zcrm_refresh_token.
242 wp_clear_scheduled_hook( 'zcrm_refresh_token' );
243
244 // Remove the mu-plugin file.
245 $mu_plugin_file = WP_CONTENT_DIR . '/mu-plugins/cmbird-media-cleanup-cli.php';
246 if ( file_exists( $mu_plugin_file ) ) {
247 wp_delete_file( $mu_plugin_file );
248 }
249 }
250
251 /**
252 * Initializes the plugin.
253 *
254 * Removes the option for Zoho Inventory access token if it contains only one character.
255 * Schedules a cronjob for import sync if the access token is not empty and the interval is not set to 'none'.
256 * Creates the webhook password if it does not exist.
257 * Loads the necessary Ajax handlers and templates.
258 *
259 * @since 1.0.0
260 */
261 public static function init() {
262 new CMBIRD_AI_Product_Blocks_Cron();
263 new CMBIRD_AI_Product_Blocks_Display();
264 new CMBIRD_AI_Product_Blocks_Block();
265
266 if ( is_admin() ) {
267 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
268 // remove option zoho_inventory_access_token if it contains only one character.
269 if ( $zoho_inventory_access_token && strlen( $zoho_inventory_access_token ) === 1 ) {
270 delete_option( 'cmbird_zoho_inventory_access_token' );
271 } else {
272 // schedule cronjob for import sync.
273 $interval = get_option( 'zi_cron_interval' );
274 if ( 'none' !== $interval && ! empty( $zoho_inventory_access_token ) ) {
275 if ( ! wp_next_scheduled( 'zi_execute_import_sync' ) ) {
276 wp_schedule_event( time(), $interval, 'zi_execute_import_sync' );
277 }
278 } else {
279 wp_clear_scheduled_hook( 'zi_execute_import_sync' );
280 }
281 }
282 // create webhook password if does not exists.
283 if ( ! get_option( 'cmbird_zi_webhook_password', false ) ) {
284 add_option( 'cmbird_zi_webhook_password', password_hash( 'commercebird-zi-webhook-token', PASSWORD_BCRYPT ) );
285 }
286 Template::instance();
287 // Load the necessary Ajax handlers and templates.
288 ZohoInventoryAjax::instance();
289 ZohoCRMAjax::instance();
290 AcfAjax::instance();
291 SettingsAjax::instance();
292 ExactOnlineAjax::instance();
293 if ( class_exists( 'ACF' ) ) {
294 AcfAjax::instance();
295 Cmbird_Acf::instance();
296 }
297 }
298 new Cmbird_WC_API();
299 new CMBIRD_Purchase_Orders_Automation();
300 }
301
302 /**
303 * Cron callback for zoho import sync interval.
304 *
305 * When the WP cron fires this hook we simply forward the request to the
306 * existing `import_simple_items_cron` action. That action is already
307 * registered in the main plugin bootstrapping script and handles batch
308 * scheduling via Action Scheduler. Passing along the arguments allows for
309 * backwards compatibility if anybody ever runs the hook manually with
310 * parameters.
311 *
312 * @since 2.7.7
313 * @param mixed ...$args Optional arguments supplied by do_action.
314 * @return void
315 */
316 public static function dispatch_import_simple_items( ...$args ) {
317 // if the event was fired with explicit arguments we simply forward them.
318 // to the existing hook (primarily useful for manual/testing purposes).
319 if ( ! empty( $args ) ) {
320 do_action( 'import_simple_items_cron', ...$args );
321 return;
322 }
323 $zi_common_class = new \CMBIRD_Common_Functions();
324 $zi_common_class->clear_orphan_data();
325
326 // categories are stored as serialized zoho ids; convert them to WC terms.
327 $zoho_item_category = get_option( 'cmbird_zoho_item_category' );
328 if ( $zoho_item_category ) {
329 // convert serialized string to array.
330 $categories = maybe_unserialize( $zoho_item_category );
331 if ( ! is_array( $categories ) ) {
332 return; // invalid format -> nothing to do.
333 }
334 } else {
335 return; // no categories configured -> nothing to do.
336 }
337 foreach ( $categories as $category_id ) {
338 $data = array(
339 'page' => 1,
340 'category' => $category_id,
341 );
342 if ( function_exists( 'as_has_scheduled_action' )
343 && ! as_has_scheduled_action( 'import_simple_items_cron', $data, 'commercebird' )
344 ) {
345 as_schedule_single_action( time(), 'import_simple_items_cron', $data, 'commercebird' );
346 }
347 }
348 }
349 }
350