load_integrations(); } } /** * Start loading all integrations. * * @return void */ public function load_integrations(): void { require_once ADPRESSO_ABSPATH . 'includes/functions/capabilities.php'; $this->load_textdomain(); add_action( 'wp', [ $this, 'gather_context' ], 0 ); $this->load_repositories(); $this->register_entities(); $this->hook( AuthorGuard::class ); // Load Module Manager first to guarantee that we can use all the hooks and filters. require_once ADPRESSO_ABSPATH . 'modules/loader.php'; $this->hook( ModuleManager::class ); require_once ADPRESSO_ABSPATH . 'includes/functions/placement.php'; require_once ADPRESSO_ABSPATH . 'includes/functions/ad.php'; require_once ADPRESSO_ABSPATH . 'includes/functions/group.php'; if ( is_admin() ) { $this->load_admin_integration(); } // admin-ajax renders frontend fragments too (streams, "load more"): shortcodes and role gates must exist there. if ( ! is_admin() || wp_doing_ajax() ) { $this->load_frontend_integrations(); } // must run during REST requests too $this->hook( MediaIntegration::class ); // Invalidates the pipeline snapshot cache. $this->hook( CacheGeneration::class ); ModuleManager::register_all_ui(); $this->hook( AdInserterBlock::class ); $this->load_rest_controllers(); $this->hook( UserRoleConditionAjaxHandler::class ); $this->hook( GlobalGatesAjaxHandler::class ); // Register Settings $settings_page = SettingsPage::get(); $settings_page->register_tab( new GeneralTab() ); $settings_page->register_tab( new FallbackTab() ); $settings_page->register_tab( new AdblockerTab() ); $this->register_conditions(); $this->register_entity_types(); // Frontend rendering logic $this->hook( Injector::class, true ); $this->hook( A2ShortcodeTakeover::class ); do_action( 'adpresso_load_integrations' ); $this->hook( Assets::class, true ); } /** * Load all integrations that are needed in admin context. * * @return void */ protected function load_admin_integration(): void { // Admin functionality $this->hook( Admin_Menu::class, true ); $this->hook( ClassicEditorRedirect::class ); $this->hook( Placement_Metaboxes_Orchestrator::class ); $this->hook( Group_Metaboxes_Orchestrator::class ); $this->hook( Ad_Metaboxes_Orchestrator::class ); $this->hook( PageAdSettings::class ); $this->hook( ImportExportManager::class, true ); $this->hook( UninstallWarning::class ); $this->hook( NotificationManager::class ); $this->hook( Premium_Availability_Debug::class ); $this->hook( Pro_Feature_Availability_Debug::class ); } /** * Load all integrations that are needed in frontend context. * * @return void */ protected function load_frontend_integrations(): void { $this->hook( Runtime::class ); $this->hook( PerformanceOptimizer::class ); $this->hook( Adminbar_Handler::class ); $this->hook( Conditionals_Debug::class ); $this->hook( Environments_Debug::class ); $this->hook( Modules_Debug::class ); $this->hook( Migration_Debug::class ); $this->hook( JsRendering_Debug::class ); $this->hook( FrontendHooks::class ); } /** * Load the text domain. * * @return void */ public function load_textdomain(): void { load_plugin_textdomain( 'adpresso', false, dirname( ADPRESSO_PLUGIN_BASENAME ) . '/languages/' ); } /** * Register all conditions. * * @return void */ protected function register_conditions(): void { $registry = Condition_Registry::get(); $registry->register_condition( new Author_Condition() ); $registry->register_condition( new BrowserLanguageCondition() ); $registry->register_condition( new Content_Age_Condition() ); $registry->register_condition( new Published_Date_Condition() ); $registry->register_condition( new Post_Condition() ); $registry->register_condition( new GeneralPageTypeCondition() ); $registry->register_condition( new TaxonomyArchiveCondition() ); $registry->register_condition( new Post_Type_Condition() ); $registry->register_condition( new ParentPageCondition() ); $registry->register_condition( new PageTemplateCondition() ); $registry->register_condition( new DeviceCondition() ); $registry->register_condition( new Taxonomy_Condition( 'category', 'category', __( 'Category', 'adpresso' ), __( 'Meta', 'adpresso' ) ) ); $registry->register_condition( new Taxonomy_Condition( 'post_tag', 'post_tag', __( 'Tag', 'adpresso' ), __( 'Meta', 'adpresso' ) ) ); do_action( 'adpresso_register_conditions', $registry ); // Custom taxonomies need to be registered late on `init` so third-party taxonomies registered on `init` themselves already exist. if ( did_action( 'init' ) ) { $this->register_custom_taxonomy_conditions( $registry ); } else { add_action( 'init', function () use ( $registry ) { $this->register_custom_taxonomy_conditions( $registry ); }, 100 ); } } /** * Registers one Taxonomy_Condition per public custom taxonomy. * * @param Condition_Registry $registry The condition registry to register into. * * @return void */ protected function register_custom_taxonomy_conditions( Condition_Registry $registry ): void { $taxonomies = get_taxonomies( [ 'public' => true, 'publicly_queryable' => true, ], 'objects' ); $excluded = array_merge( [ 'category', 'post_tag' ], (array) apply_filters( 'adpresso_condition_taxonomy_excluded_taxonomies', [] ) ); foreach ( $taxonomies as $taxonomy ) { if ( in_array( $taxonomy->name, $excluded, true ) ) { continue; } $registry->register_condition( new Taxonomy_Condition( $taxonomy->name, 'taxonomy_' . $taxonomy->name, $taxonomy->labels->name, __( 'Taxonomies', 'adpresso' ) ) ); } } /** * Register the entities. * * @return void */ protected function register_entities(): void { // Entity & CPT setup $this->hook( \AdPresso\Placements\Registrar::class ); $this->hook( \AdPresso\Ads\Registrar::class ); $this->hook( Registrar::class ); do_action( 'adpresso_register_entities' ); } /** * @return void */ protected function register_entity_types(): void { $placement_type_registry = PlacementTypeRegistry::get(); $ad_type_registry = AdTypeRegistry::get(); $group_type_registry = GroupTypeRegistry::get(); $placement_type_registry->register( new Content() ); $placement_type_registry->register( new Header() ); $placement_type_registry->register( new Footer() ); $placement_type_registry->register( new BeforeContent() ); $placement_type_registry->register( new AfterContent() ); $placement_type_registry->register( new Manual() ); $ad_type_registry->register( new Dummy() ); $ad_type_registry->register( new Html() ); $ad_type_registry->register( new Image() ); $ad_type_registry->register( new Html5() ); $group_type_registry->register( new DefaultGroup() ); AdFieldRegistry::get(); PlacementFieldRegistry::get(); GroupFieldRegistry::get(); do_action( 'adpresso_placement_types_registered', $placement_type_registry ); do_action( 'adpresso_ad_types_registered', $ad_type_registry ); do_action( 'adpresso_group_types_registered', $group_type_registry ); } /** * Load all repositories that are needed and save them persistently in the globals array. * * @return void */ public function load_repositories(): void { $this->hook( PlacementRepository::class, true ); $this->hook( AdRepository::class, true ); $this->hook( GroupRepository::class, true ); do_action( 'adpresso_load_repositories' ); } /** * Load all REST controllers that are needed. * * @return void */ public function load_rest_controllers(): void { // wp_ajax_* handler - registers on admin-ajax, so it can't wait for rest_api_init. $this->hook( DebugTokenAjaxHandler::class ); // The rest only need to exist on a REST request. Priority 5 so each controller's own register_routes (added at the default priority 10 from its hooks()/constructor) still runs in the same rest_api_init pass. add_action( 'rest_api_init', function () { $this->hook( PlacementController::class ); $this->hook( AdController::class ); $this->hook( GroupController::class ); $this->hook( AssignmentController::class ); $this->hook( FilterOptionsController::class ); $this->hook( BulkActionsController::class ); $this->hook( GeneralController::class ); $this->hook( GlobalSearchHandler::class ); $this->hook( Html5ExtractController::class ); do_action( 'adpresso_load_rest_controllers' ); }, 5 ); } /** * @param string $class_name * @param bool $persistent * * @return void */ private function hook( string $class_name, bool $persistent = false ): void { if ( ! class_exists( $class_name ) ) { return; } try { $instance = new $class_name(); } catch ( \Throwable ) { // A class that can't be instantiated is skipped silently. Errors from hooks() below are deliberately left to surface. return; } if ( method_exists( $instance, 'hooks' ) ) { $instance->hooks(); } if ( $persistent ) { $this->globals[ $class_name ] = $instance; } } /** * Gather internal context information for the current request. * Can be used for tests. * * @return void */ public function gather_context(): void { global $wp_query; // admin-ajax.php counts as admin, but renders frontend fragments (activity streams, "load more"). if ( is_admin() && ! wp_doing_ajax() ) { return; } $queried = get_queried_object(); if ( is_singular() ) { $post_type = $queried->post_type ?? null; } elseif ( is_post_type_archive() ) { $post_type = get_query_var( 'post_type' ); if ( is_array( $post_type ) ) { $post_type = reset( $post_type ) ?: null; } } else { $post_type = null; } $this->context = [ 'is_singular' => is_singular(), 'is_page' => is_page(), 'is_post' => is_singular( 'post' ), 'is_single' => is_single(), 'is_home' => is_home(), 'is_front_page' => is_front_page(), 'is_archive' => is_archive(), 'is_attachment' => is_attachment(), 'is_post_type_archive' => is_post_type_archive(), 'is_category' => is_category(), 'is_tag' => is_tag(), 'is_tax' => is_tax(), 'is_author' => is_author(), 'is_search' => is_search(), 'is_404' => is_404(), 'post_type' => $post_type, 'queried_object_id' => $wp_query->queried_object_id ?? null, 'queried_object' => $wp_query->queried_object ?? null, 'current_time_gmt' => current_time( 'mysql', true ), 'request_uri' => Params::server()->get( 'REQUEST_URI' ), ]; } }