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