urldecode( sanitize_title( $title ) ); $this->settings = new Settings(); $this->globals = new GlobalTabs(); $this->product_tabs = new ProductTabs(); $this->resolver = new TabResolver( $slugify ); $this->renderer = new TabRenderer( $this->settings, $this->globals, $this->product_tabs, $this->resolver ); $this->block_compat = new BlockCompat( $this->settings, $this->product_tabs, $this->renderer ); $this->importer = new YikesImporter( new YikesMapper( $slugify ), $this->product_tabs, $this->globals ); } /** * Instance (null before boot or when WooCommerce is missing). */ public static function instance(): ?Plugin { return self::$instance; } /** * Boot on plugins_loaded. */ public static function boot(): void { if ( null !== self::$instance ) { return; } if ( ! self::woocommerce_ready() ) { add_action( 'admin_notices', array( self::class, 'missing_woocommerce_notice' ) ); return; } self::$instance = new self(); self::$instance->register(); /** * Fires when the plugin is ready. Add-ons receive the service container. * * @param Plugin $plugin Plugin. */ do_action( 'pnscripts_product_tabs_loaded', self::$instance ); } /** * Register hooks. */ private function register(): void { add_action( 'update_option_' . Settings::OPTION, array( $this->settings, 'flush' ) ); $this->globals->register(); $this->product_tabs->register(); $this->renderer->register(); $this->block_compat->register(); if ( is_admin() ) { ( new ProductPanel( $this->globals, $this->product_tabs ) )->register(); ( new GlobalTabMetaBox( $this->globals ) )->register(); ( new SettingsPage( $this->settings, $this->importer ) )->register(); } if ( defined( 'WP_CLI' ) && WP_CLI && class_exists( '\WP_CLI' ) ) { $command = new Command( $this ); \WP_CLI::add_command( 'pnscripts-tabcrest', $command ); // 1.0.x name, kept so existing scripts keep working. \WP_CLI::add_command( 'pnscripts-product-tabs', $command ); } } /** * Active licence implementation (free no-op unless an add-on provides one). */ public function license(): LicenseInterface { $license = apply_filters( 'pnscripts_product_tabs_license', null ); return $license instanceof LicenseInterface ? $license : new FreeLicense(); } /** * WooCommerce active in a supported version. */ private static function woocommerce_ready(): bool { return class_exists( 'WooCommerce' ) && defined( 'WC_VERSION' ) && version_compare( (string) WC_VERSION, PNSCRIPTS_PRODUCT_TABS_MIN_WC, '>=' ); } /** * Admin notice when WooCommerce is too old (WordPress itself blocks activation without it). */ public static function missing_woocommerce_notice(): void { if ( ! current_user_can( 'activate_plugins' ) ) { return; } // Only on the Plugins screen, where the dependency is managed. $screen = get_current_screen(); if ( null === $screen || 'plugins' !== $screen->id ) { return; } printf( '

%s

', esc_html( sprintf( /* translators: %s: minimum WooCommerce version */ __( 'PN Scripts Tabcrest needs WooCommerce %s or newer to be active.', 'pnscripts-tabcrest' ), PNSCRIPTS_PRODUCT_TABS_MIN_WC ) ) ); } }