*/ private $modules = array(); /** * Whether register_hooks() has already run. * * @since 1.0.0 * @var bool */ private $hooks_registered = false; /** * Constructor is private; use instance(). * * @since 1.0.0 */ private function __construct() {} /** * Returns the shared instance. * * @since 1.0.0 * * @return Core Shared instance. */ public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Adds a feature module to the registry. * * Registering the same slug twice replaces the earlier instance, which lets * a test or an add-on substitute a module without duplicating its hooks. A * module added after register_hooks() has run is hooked immediately so that * registration order does not change behaviour. * * @since 1.0.0 * * @param ModuleInterface $module Module to register. * @return void */ public function register_module( ModuleInterface $module ) { $this->modules[ $module->slug() ] = $module; if ( $this->hooks_registered ) { $module->register_hooks(); } } /** * Returns the registered modules. * * @since 1.0.0 * * @return array Modules keyed by slug. */ public function modules() { return $this->modules; } /** * Returns one registered module by slug. * * @since 1.0.0 * * @param string $slug Module slug. * @return ModuleInterface|null Module, or null when not registered. */ public function module( $slug ) { return isset( $this->modules[ $slug ] ) ? $this->modules[ $slug ] : null; } /** * Registers the plugin's WordPress hooks and those of every module. * * Idempotent: Activator calls it defensively to guarantee the custom cron * recurrences exist before it schedules against them. * * @since 1.0.0 * * @return void */ public function register_hooks() { if ( $this->hooks_registered ) { return; } $this->hooks_registered = true; add_filter( 'cron_schedules', array( self::class, 'register_cron_schedules' ) ); // phpcs:ignore WordPress.WP.CronInterval.ChangeDetected -- Both added recurrences are 6 hours or longer. add_action( 'init', array( $this, 'load_textdomain' ) ); add_action( 'admin_init', array( Database::class, 'maybe_upgrade' ) ); foreach ( $this->modules as $module ) { $module->register_hooks(); } } /** * Adds the plugin's custom cron recurrences. * * `aive_daily` duplicates core's `daily` interval on purpose: owning the * recurrence means a site that filters core's schedules cannot accidentally * unschedule AIVE's cleanup job. * * @since 1.0.0 * * @param array|mixed $schedules Registered cron schedules. * @return array Schedules including the plugin's own. */ public static function register_cron_schedules( $schedules ) { if ( ! is_array( $schedules ) ) { $schedules = array(); } $schedules[ self::SCHEDULE_EVERY_6_HOURS ] = array( 'interval' => 6 * HOUR_IN_SECONDS, 'display' => __( 'Every 6 hours (SummitCite)', 'summitcite' ), ); $schedules[ self::SCHEDULE_DAILY ] = array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once daily (SummitCite)', 'summitcite' ), ); return $schedules; } /** * Loads the plugin text domain. * * @since 1.0.0 * * @return void */ public function load_textdomain() { load_plugin_textdomain( 'summitcite', false, dirname( plugin_basename( AIVE_PLUGIN_FILE ) ) . '/languages' ); } }