setup(); } /** * Activation: create or upgrade stored data. Never deletes anything. * Also schedules the update guard's baseline, so the first update is * checked even on a site that is only managed with WP-CLI. */ public static function activate() { Migrations::maybe_run(); UpdateGuard::schedule_baseline( new Settings() ); } /** * Deactivation: stop scheduled work. User data is kept. */ public static function deactivate() { wp_clear_scheduled_hook( Jobs::HOOK ); wp_clear_scheduled_hook( Maintenance::HOOK ); wp_clear_scheduled_hook( Monitor::HOOK ); wp_clear_scheduled_hook( Autopilot::SCAN_HOOK ); wp_clear_scheduled_hook( IndexNow::HOOK ); wp_clear_scheduled_hook( 'orbitstem_seo_indexnow_send' ); // Cron hook name used by 1.1.0 test builds. wp_clear_scheduled_hook( UpdateGuard::HOOK ); wp_clear_scheduled_hook( UpdateGuard::BASELINE_HOOK ); // A baseline from before deactivation would be stale when the plugin comes back. delete_option( UpdateGuard::BASELINE ); } /** * Wires services together. */ private function setup() { Migrations::maybe_run(); $this->settings = new Settings(); $this->types = new TypeRegistry( $this->settings ); $this->meta = new MetaRepository(); $this->templates = new TemplateEngine( $this->settings ); $this->resolver = new Resolver( $this->settings, $this->types, $this->meta, $this->templates ); $this->detector = new PluginDetector(); $this->jobs = new Jobs(); $this->trail = new Trail( $this->settings, $this->types ); $this->local = new LocalBusiness( $this->settings ); $this->graph = new Graph( $this->settings, $this->meta, $this->local ); $this->importer = new Importer( $this->meta, $this->jobs ); $this->links = new Index( $this->types ); $sitemap_scan = new SitemapScan( $this->settings, $this->types, $this->resolver ); $head_inspector = new HeadInspector( $this->types ); $url_checker = new UrlChecker( $this->settings ); $this->scanner = new Scanner( $this->jobs, $this->links, $sitemap_scan, $url_checker, $head_inspector ); $this->changes = new ChangeLog(); $this->redirects = new Repository( $this->changes ); $this->not_found = new NotFoundLog(); $chains = new ChainAnalyzer( $this->redirects ); $this->issues = new Issues( $this->settings, $this->types, $sitemap_scan, $head_inspector, $chains ); $this->suggester = new Suggester( $this->settings, $this->types, $this->meta ); $this->repair = new RepairCenter( $this->changes, array( new RedirectedLinks( $url_checker ), new RedirectChains( $this->redirects, $chains ), new BrokenLinks( $url_checker ), new RedirectEdits( $this->redirects ), new OutdatedLinks( $url_checker ), new OrphanLinks( $url_checker, $this->issues, $this->suggester ), new SiteEvents(), new GuardianChanges( $this->redirects ), new CsvImport( $this->meta ), new SettingsImport(), ) ); $this->importer->set_log( $this->changes ); $this->csv = new SeoCsv( $this->meta, $this->types, $this->changes ); $this->impact = new Impact( $this->settings, $this->resolver ); $this->guardian = new Guardian( $this->settings, $this->types, $this->redirects, $this->changes, $this->impact ); $this->snapshots = new Snapshotter( $this->settings, $this->types, $this->resolver, $head_inspector, $this->jobs, function () { return array( 'output_enabled' => $this->output_enabled(), 'seo_plugins' => array_values( wp_list_pluck( $this->detector->detect(), 'name' ) ), ); } ); $this->diff = new Diff( $this->snapshots ); $this->monitor = new Monitor( $this->settings, $this->snapshots, $this->diff ); $this->autopilot = new Autopilot( $this->settings, $this->jobs, $this->scanner, $this->repair, $this->changes, $url_checker ); $this->issues->add_provider( array( $this->monitor, 'issues' ) ); $this->guard = new UpdateGuard( $this->settings, $this->changes ); $this->issues->add_provider( array( $this->guard, 'issues' ) ); $cannibals = new Cannibals( $this->settings, $this->types ); $cannibals->register(); $this->issues->add_provider( array( $cannibals, 'issues' ) ); $this->indexnow = new IndexNow( $this->settings, $this->types, $this->meta ); add_action( 'init', array( $this->meta, 'register' ), 20 ); // Settings are cleaned on every save, not only from the settings screen (WP-CLI, code, imports). // Same callback and priority as register_setting() in Admin, so it never runs twice. add_filter( 'sanitize_option_' . Settings::OPTION, array( Settings::class, 'sanitize' ) ); $this->jobs->register_hooks(); UrlChecker::register_hooks(); add_action( 'orbitstem_seo_register_jobs', array( $this->importer, 'register' ) ); add_action( 'orbitstem_seo_register_jobs', array( $this->scanner, 'register' ) ); add_action( 'orbitstem_seo_register_jobs', array( $this->snapshots, 'register' ) ); $this->trail->register(); $this->links->register(); ( new Runtime( $this->redirects, $this->not_found, $this->settings ) )->register(); ( new Maintenance( $this->settings, $this->not_found, $this->changes ) )->register(); $this->guardian->register(); $this->monitor->register(); $this->autopilot->register(); $this->suggester->register(); $this->local->register(); $this->guard->register(); ( new HealthEmail( $this->settings, $this->issues ) )->register(); ( new RestController( $this->impact, $this->suggester ) )->register(); // Safe mode: while another SEO plugin is active, nothing here changes what // visitors or search engines see (robots.txt, llms.txt, IndexNow, sitemaps). $this->indexnow->set_safe_mode( ! $this->output_enabled() ); $this->indexnow->register_cron(); if ( $this->output_enabled() ) { $this->indexnow->register(); ( new Robots( $this->settings, $this->types, $this->resolver ) )->register(); ( new HeadOutput( $this->resolver, $this->settings, $this->graph, $this->trail ) )->register(); ( new CoreSitemaps( $this->settings, $this->types ) )->register(); ( new ExtraSitemaps( $this->settings, $this->types, $this->meta ) )->register(); if ( $this->settings->get( 'schema_enabled' ) && Woo::active() ) { Woo::register( (bool) $this->settings->get( 'woo_schema' ) ); } } if ( defined( 'WP_CLI' ) && WP_CLI ) { \Orbitstem\SEO\Cli\Command::register( $this ); } if ( is_admin() ) { \Orbitstem\SEO\Admin\Ui::register(); ( new Admin( $this ) )->register(); ( new PostMetaBox( $this ) )->register(); ( new TermFields( $this ) )->register(); ( new BulkEditor( $this ) )->register(); ( new ImportPage( $this, $this->importer ) )->register(); ( new IssuesPage( $this ) )->register(); ( new RedirectsPage( $this ) )->register(); ( new RepairPage( $this ) )->register(); ( new GuardianPage( $this ) )->register(); ( new MonitorPage( $this ) )->register(); ( new \Orbitstem\SEO\Admin\SetupPage( $this ) )->register(); } } /** * Front-end output runs unless another SEO plugin is active (safe mode), * in which case the user must opt in explicitly. * * @return bool */ public function output_enabled() { $enabled = ! $this->detector->has_conflicts() || (bool) $this->settings->get( 'force_output' ); /** * Filters whether Orbitstem SEO prints its head tags. * * @param bool $enabled Whether output is enabled. */ return (bool) apply_filters( 'orbitstem_seo_output_enabled', $enabled ); } }