' . esc_html__( 'ABCT Smart Orders Free was not initialized because ABCT Smart Orders Pro is active. Keep only Pro enabled on this site.', 'abct-smart-orders' ) . '

'; }; add_action( 'admin_notices', $abct_so_free_conflict_notice ); add_action( 'network_admin_notices', $abct_so_free_conflict_notice ); return; } if ( ! defined( 'ABCT_SO_FREE_BOOTSTRAPPED' ) ) { define( 'ABCT_SO_FREE_BOOTSTRAPPED', true ); } define( 'ABCT_SO_VERSION', '1.5.10' ); define( 'ABCT_SO_DB_VERSION', '1.5.0' ); define( 'ABCT_SO_PLUGIN_FILE', __FILE__ ); define( 'ABCT_SO_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'ABCT_SO_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); if ( ! defined( 'ABCT_PRODUCT_SLUG' ) ) { define( 'ABCT_PRODUCT_SLUG', 'abctransfer-smart-orders' ); } /** * Loaded files errors. * * @var array */ $GLOBALS['abct_so_load_errors'] = array(); /** * Safely include plugin files. * * @param string $relative_path Relative plugin path. * @return bool */ function abct_so_safe_require( $relative_path ) { $file_path = ABCT_SO_PLUGIN_DIR . ltrim( $relative_path, '/' ); if ( ! file_exists( $file_path ) ) { $GLOBALS['abct_so_load_errors'][] = sprintf( /* translators: %s: missing file path */ __( 'Missing required file: %s', 'abct-smart-orders' ), str_replace( ABCT_SO_PLUGIN_DIR, '', $file_path ) ); return false; } try { require_once $file_path; return true; } catch ( Throwable $e ) { $GLOBALS['abct_so_load_errors'][] = sprintf( /* translators: %s: file path */ __( 'Failed loading file safely: %s', 'abct-smart-orders' ), str_replace( ABCT_SO_PLUGIN_DIR, '', $file_path ) ); error_log( '[ABCT Smart Orders] Safe require error (' . $relative_path . '): ' . $e->getMessage() ); return false; } } abct_so_safe_require( 'includes/class-abct-status.php' ); abct_so_safe_require( 'includes/class-abct-status-manager.php' ); abct_so_safe_require( 'includes/database.php' ); abct_so_safe_require( 'includes/functions-hours.php' ); abct_so_safe_require( 'includes/upsell-functions.php' ); abct_so_safe_require( 'admin/settings-page.php' ); /** * Resolve operational capability. * * @return string */ function abct_get_operations_capability() { /** * Filter operational capability for ABCT runtime. * * @param string $capability Capability key. */ return (string) apply_filters( 'abct_operations_capability', 'manage_woocommerce' ); } /** * Check if current user can operate ABCT operational flows. * * @return bool */ function abct_user_can_manage_operations() { return current_user_can( abct_get_operations_capability() ); } /** * Register explicit Orders module menu in admin. * * @return string */ function abct_resolve_orders_parent_menu() { global $menu; $registered = array(); if ( is_array( $menu ) ) { foreach ( $menu as $item ) { if ( is_array( $item ) && ! empty( $item[2] ) ) { $registered[] = (string) $item[2]; } } } if ( in_array( 'abct-live-orders', $registered, true ) ) { return 'abct-live-orders'; } if ( in_array( 'abct-store-settings', $registered, true ) ) { return 'abct-store-settings'; } return ''; } /** * Register explicit Orders module menu in admin. * * @return void */ function abct_register_orders_module() { $capability = abct_get_operations_capability(); $parent = abct_resolve_orders_parent_menu(); if ( '' !== $parent ) { add_submenu_page( $parent, __( 'Orders', 'abct-smart-orders' ), __( 'Orders', 'abct-smart-orders' ), $capability, 'abct-production-board', 'abct_render_production_board' ); return; } add_menu_page( __( 'ABCT Orders', 'abct-smart-orders' ), __( 'Orders', 'abct-smart-orders' ), $capability, 'abct-production-board', 'abct_render_production_board', 'dashicons-list-view', 56 ); } if ( apply_filters( 'abct_enable_legacy_orders_menu', false ) ) { add_action( 'admin_menu', 'abct_register_orders_module' ); } /** * Render production board callback. * * @return void */ function abct_render_production_board() { $page_file = plugin_dir_path( __FILE__ ) . 'admin/production-board-page.php'; if ( ! file_exists( $page_file ) ) { echo '

' . esc_html__( 'Production Board', 'abct-smart-orders' ) . '

' . esc_html__( 'Production Board is available in Smart Orders Pro.', 'abct-smart-orders' ) . '

'; return; } require_once $page_file; if ( function_exists( 'abct_render_production_board_page' ) ) { abct_render_production_board_page(); } } /** * Legacy Orders module asset bridge. * * Reuses the canonical Production Board enqueue/localize pipeline * to avoid duplicate bootstrap, duplicate polling and payload drift. * * @param string $hook Current admin hook. * @return void */ function abct_enqueue_orders_module_assets( $hook ) { if ( ! in_array( $hook, array( 'toplevel_page_abct-production-board', 'abct-live-orders_page_abct-production-board', 'abct-store-settings_page_abct-production-board' ), true ) ) { return; } if ( function_exists( 'abct_enqueue_production_board_assets' ) ) { abct_enqueue_production_board_assets( $hook ); } } if ( apply_filters( 'abct_enable_legacy_orders_menu', false ) ) { add_action( 'admin_enqueue_scripts', 'abct_enqueue_orders_module_assets' ); } /** * Fallback activation callback. * * @return void */ function abct_so_activate_plugin() { if ( function_exists( 'abct_activate_plugin' ) ) { abct_activate_plugin(); } } register_activation_hook( ABCT_SO_PLUGIN_FILE, 'abct_so_activate_plugin' ); /** * Deactivation callback. * * @return void */ function abct_so_deactivate_plugin() { if ( function_exists( 'abct_queue_clear_cleanup_schedule' ) ) { abct_queue_clear_cleanup_schedule(); } } register_deactivation_hook( ABCT_SO_PLUGIN_FILE, 'abct_so_deactivate_plugin' ); /** * Check WooCommerce status without forcing dependency. * * @return bool */ function abct_so_is_woocommerce_active() { if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } return function_exists( 'is_plugin_active' ) && is_plugin_active( 'woocommerce/woocommerce.php' ); } /** * Main plugin class. */ class ABCT_Smart_Orders { /** * Indicates if modular core loaded. * * @var bool */ private $core_loaded = false; /** * Constructor. */ public function __construct() { add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) ); // FIX: Ensure DB schema is upgraded for existing installs. add_action( 'plugins_loaded', array( $this, 'maybe_upgrade_database' ), 20 ); add_action( 'admin_notices', array( $this, 'render_admin_notices' ) ); add_action( 'plugins_loaded', array( $this, 'bootstrap_core' ), 30 ); add_action( 'admin_menu', array( $this, 'maybe_register_legacy_admin_menu' ), 20 ); add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_legacy_admin_assets' ) ); } /** * Load plugin textdomain. * * @return void */ public function load_textdomain() { load_plugin_textdomain( 'abct-smart-orders', false, dirname( plugin_basename( ABCT_SO_PLUGIN_FILE ) ) . '/languages' ); } /** * Upgrade DB schema when needed. * * @return void */ public function maybe_upgrade_database() { if ( function_exists( 'abct_maybe_upgrade_database' ) ) { abct_maybe_upgrade_database(); } } /** * Bootstrap modular core loader. * * @return void */ public function bootstrap_core() { $core_files = array( 'core/class-abct-core-container.php', 'core/class-abct-module-interface.php', 'modules/scheduling/class-abct-scheduling-module.php', 'modules/menu/class-abct-menu-module.php', 'core/class-abct-core-loader.php', ); foreach ( $core_files as $core_file ) { try { if ( ! abct_so_safe_require( $core_file ) ) { return; } } catch ( Throwable $e ) { $GLOBALS['abct_so_load_errors'][] = __( 'A core module failed to load safely. Using legacy admin fallback.', 'abct-smart-orders' ); error_log( '[ABCT Smart Orders] Core file load error: ' . $e->getMessage() ); return; } } $required = array( 'ABCT_Core_Loader', 'ABCT_Core_Container', 'ABCT_Module_Interface', 'ABCT_Scheduling_Module', 'ABCT_Menu_Module', ); foreach ( $required as $class_name ) { if ( class_exists( $class_name ) || interface_exists( $class_name ) ) { continue; } $GLOBALS['abct_so_load_errors'][] = sprintf( /* translators: %s: class name */ __( 'Missing required class: %s', 'abct-smart-orders' ), $class_name ); error_log( '[ABCT Smart Orders] Missing required class: ' . $class_name ); return; } try { ABCT_Core_Loader::boot(); $this->core_loaded = true; } catch ( Throwable $e ) { $GLOBALS['abct_so_load_errors'][] = __( 'Core modules failed to initialize safely. Check server error log.', 'abct-smart-orders' ); error_log( '[ABCT Smart Orders] Core bootstrap error: ' . $e->getMessage() ); } } /** * Register legacy admin menu only if modular core is unavailable. * * @return void */ public function maybe_register_legacy_admin_menu() { if ( $this->core_loaded && $this->is_admin_menu_registered( 'abct-smart-orders' ) ) { return; } $this->register_admin_menu(); } /** * Check if an admin menu slug is already registered. * * @param string $menu_slug Menu slug. * @return bool */ private function is_admin_menu_registered( $menu_slug ) { global $menu; if ( empty( $menu ) || ! is_array( $menu ) ) { return false; } foreach ( $menu as $item ) { if ( ! is_array( $item ) || empty( $item[2] ) ) { continue; } if ( (string) $menu_slug === (string) $item[2] ) { return true; } } return false; } /** * Resolve a safe admin capability for legacy menu fallback. * * @return string */ private function get_legacy_menu_capability() { $capability = abct_get_operations_capability(); if ( current_user_can( $capability ) ) { return $capability; } return 'manage_options'; } /** * Enqueue legacy assets only if modular core is unavailable. * * @param string $hook Hook suffix. * @return void */ public function maybe_enqueue_legacy_admin_assets( $hook ) { if ( $this->core_loaded ) { return; } $this->enqueue_admin_assets( $hook ); } /** * Render plugin load warnings. * * @return void */ public function render_admin_notices() { if ( ! current_user_can( 'manage_options' ) ) { return; } if ( ! abct_so_is_woocommerce_active() ) { echo '

' . esc_html__( 'ABCT Smart Orders:', 'abct-smart-orders' ) . ' ' . esc_html__( 'WooCommerce is not available.', 'abct-smart-orders' ) . '

'; } if ( empty( $GLOBALS['abct_so_load_errors'] ) || ! is_array( $GLOBALS['abct_so_load_errors'] ) ) { return; } echo '

' . esc_html__( 'ABCTransfer Smart Orders:', 'abct-smart-orders' ) . '

'; } /** * Register admin menus. * * @return void */ public function register_admin_menu() { $capability = $this->get_legacy_menu_capability(); $live_callback = array( $this, 'render_missing_live_orders_page' ); $settings_callback = function_exists( 'abct_render_settings_page' ) ? 'abct_render_settings_page' : array( $this, 'render_missing_settings_page' ); add_menu_page( __( 'Smart Orders', 'abct-smart-orders' ), __( 'Smart Orders', 'abct-smart-orders' ), $capability, 'abct-smart-orders', $live_callback, 'dashicons-store', 56 ); add_submenu_page( 'abct-smart-orders', __( 'Store Schedule', 'abct-smart-orders' ), __( 'Store Schedule', 'abct-smart-orders' ), $capability, 'abct-edit-schedule', $settings_callback ); } /** * Fallback renderer when live orders callback is unavailable. * * @return void */ public function render_missing_live_orders_page() { echo '

' . esc_html__( 'Smart Orders Free', 'abct-smart-orders' ) . '

' . esc_html__( 'Core modules are temporarily unavailable. Please reload this page.', 'abct-smart-orders' ) . '

'; } /** * Fallback renderer when settings callback is unavailable. * * @return void */ public function render_missing_settings_page() { echo '

' . esc_html__( 'Edit Schedule', 'abct-smart-orders' ) . '

' . esc_html__( 'Settings page callback is unavailable.', 'abct-smart-orders' ) . '

'; } /** * Enqueue admin styles/scripts. * * @param string $hook Hook suffix. * @return void */ public function enqueue_admin_assets( $hook ) { if ( ! in_array( $hook, array( 'toplevel_page_abct-live-orders', 'abct-live-orders_page_abct-edit-schedule' ), true ) ) { return; } wp_enqueue_style( 'abct-admin', ABCT_SO_PLUGIN_URL . 'assets/css/admin.css', array(), ABCT_SO_VERSION ); if ( 'toplevel_page_abct-live-orders' !== $hook ) { return; } wp_enqueue_script( 'abct-orders', ABCT_SO_PLUGIN_URL . 'assets/js/orders.js', array( 'jquery' ), ABCT_SO_VERSION, true ); wp_localize_script( 'abct-orders', 'abctOrders', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'abct_orders_nonce' ), 'pollInterval' => 5000, 'soundUrl' => ABCT_SO_PLUGIN_URL . 'assets/sounds/sound_1.mp3', 'i18n' => array( 'customer' => __( 'Customer', 'abct-smart-orders' ), 'phone' => __( 'Phone', 'abct-smart-orders' ), 'total' => __( 'Total', 'abct-smart-orders' ), 'createdAt' => __( 'Created at', 'abct-smart-orders' ), 'orderData' => __( 'Order Data', 'abct-smart-orders' ), 'noOrders' => __( 'No orders found.', 'abct-smart-orders' ), 'new' => __( 'New', 'abct-smart-orders' ), 'preparing' => __( 'Preparing', 'abct-smart-orders' ), 'finished' => __( 'Finished', 'abct-smart-orders' ), ), ) ); } } new ABCT_Smart_Orders();