settings = new Settings(); $this->catalog = new Catalog( $this->settings ); $this->assets = new Assets( $this->settings ); $this->boot(); } /** * Settings repository accessor. * * @return Settings */ public function settings() { return $this->settings; } /** * Catalog service accessor. * * @return Catalog */ public function catalog() { return $this->catalog; } /** * Asset loader accessor. * * @return Assets */ public function assets() { return $this->assets; } /** * Register the plugin hooks. * * The admin settings screen always loads so it stays reachable even when * WooCommerce is missing — only the frontend integration is gated. * * @return void */ private function boot() { // Priority 1 so extensions announced on this hook have registered // their listeners: they boot on `plugins_loaded`, which runs before // any `init` callback. add_action( 'init', array( $this, 'announce_loaded' ), 1 ); if ( is_admin() ) { new Admin\Admin( $this->settings, $this->catalog ); add_filter( 'plugin_action_links_' . BULKORA_BASE, array( $this, 'action_links' ) ); } if ( ! $this->has_woocommerce() ) { add_action( 'admin_notices', array( $this, 'notice_missing_woocommerce' ) ); return; } if ( ! $this->meets_minimum_wc_version() ) { add_action( 'admin_notices', array( $this, 'notice_minimum_woocommerce' ) ); return; } // Registering assets and loading modules both translate strings, and // translations are only available from `init` onward. Doing this on // `plugins_loaded` triggers the "_load_textdomain_just_in_time" // warning, so defer it. add_action( 'init', array( $this, 'init_integration' ), 20 ); } /** * Boot the WooCommerce integration once translations are available. * * @return void */ public function init_integration() { $this->assets->register_hooks(); new Managers\Module_Manager( $this->catalog ); } /** * Announce that the free plugin is ready for extensions. * * @return void */ public function announce_loaded() { /** * Fires once the free plugin's services are ready. * * Extensions (such as the Pro plugin) hook here to register their own * modules, settings and assets. Fired on `init` so every plugin has * had the chance to register a listener. * * @param Plugin $plugin The plugin container. */ do_action( 'bulkora_loaded', $this ); } /** * Whether WooCommerce is active and past the loading gate. * * @return bool */ private function has_woocommerce() { return class_exists( 'WooCommerce' ) && defined( 'WC_VERSION' ); } /** * Whether the installed WooCommerce build is new enough. * * @return bool */ private function meets_minimum_wc_version() { return defined( 'WC_VERSION' ) && version_compare( WC_VERSION, BULKORA_MIN_WC_VERSION, '>=' ); } /** * Cache-busting version string for an asset. * * Uses the file's modification time so a rebuilt stylesheet or script is * never served from the browser cache under an unchanged plugin version. * * @param string $relative Path relative to the assets directory. * @return string */ public static function asset_version( $relative ) { $file = BULKORA_PATH . 'assets/' . ltrim( (string) $relative, '/' ); if ( is_readable( $file ) ) { return BULKORA_VERSION . '.' . filemtime( $file ); } return BULKORA_VERSION; } /** * Add a settings shortcut to the plugins list row. * * @param array $links Existing action links. * @return array */ public function action_links( $links ) { $settings = sprintf( '%s', esc_url( admin_url( 'admin.php?page=' . Admin\Admin::PAGE_SETTINGS ) ), esc_html__( 'Settings', 'bulkora-multiple-variation-order' ) ); array_unshift( $links, $settings ); return $links; } /** * Warn that WooCommerce is required. * * @return void */ public function notice_missing_woocommerce() { if ( ! current_user_can( 'activate_plugins' ) ) { return; } $installed = $this->is_woocommerce_installed(); $action = $installed ? $this->woocommerce_activate_button() : $this->woocommerce_install_button(); printf( '
%s
%s%s