indexer = $indexer ?? new Indexer(); } /** * Register hooks. */ public function register(): void { // Change detection. add_action( 'save_post', array( $this, 'on_save_post' ), 20, 2 ); add_action( 'deleted_post', array( $this, 'on_post_gone' ) ); add_action( 'trashed_post', array( $this, 'on_post_gone' ) ); add_action( 'updated_post_meta', array( $this, 'on_meta_change' ), 10, 3 ); add_action( 'added_post_meta', array( $this, 'on_meta_change' ), 10, 3 ); add_action( 'wp_update_nav_menu', array( $this, 'on_menu_change' ) ); add_action( 'wp_delete_nav_menu', array( $this, 'on_menu_change' ) ); add_action( 'update_option_sidebars_widgets', array( $this, 'on_widgets_change' ) ); foreach ( array_keys( WidgetExtractor::WIDGETS ) as $option ) { add_action( 'update_option_' . $option, array( $this, 'on_widgets_change' ) ); add_action( 'add_option_' . $option, array( $this, 'on_widgets_change' ) ); } add_action( 'wp_insert_comment', array( $this, 'on_comment_change' ) ); add_action( 'edit_comment', array( $this, 'on_comment_change' ) ); add_action( 'wp_set_comment_status', array( $this, 'on_comment_change' ) ); add_action( 'deleted_comment', array( $this, 'on_comment_change' ) ); // Background job handlers. add_action( self::HOOK_POST, array( $this, 'handle_post' ) ); add_action( self::HOOK_MENUS, array( $this, 'handle_menus' ) ); add_action( self::HOOK_WIDGETS, array( $this, 'handle_widgets' ) ); add_action( self::HOOK_COMMENT, array( $this, 'handle_comment' ) ); } /** * Enqueue re-extraction for a saved post. * * @param int $post_id Post ID. * @param \WP_Post $post Post. */ public function on_save_post( $post_id, $post ): void { if ( ! $post instanceof \WP_Post || wp_is_post_revision( $post ) || wp_is_post_autosave( $post ) ) { return; } if ( 'nav_menu_item' === $post->post_type ) { Jobs::enqueue_unique( self::HOOK_MENUS ); return; } if ( ! in_array( $post->post_type, Indexer::post_types(), true ) ) { return; } // Drafts are enqueued too: the job removes instances of posts that are no longer published. Jobs::enqueue_unique( self::HOOK_POST, array( (int) $post_id ) ); } /** * Enqueue cleanup for a trashed or deleted post. * * @param int $post_id Post ID. */ public function on_post_gone( $post_id ): void { Jobs::enqueue_unique( self::HOOK_POST, array( (int) $post_id ) ); } /** * Elementor writes its data as post meta; re-extract when it changes. * * @param int $meta_id Meta ID. * @param int $post_id Post ID. * @param string $meta_key Meta key. */ public function on_meta_change( $meta_id, $post_id, $meta_key ): void { if ( ElementorExtractor::META_KEY === $meta_key || '_menu_item_url' === $meta_key ) { if ( '_menu_item_url' === $meta_key ) { Jobs::enqueue_unique( self::HOOK_MENUS ); return; } Jobs::enqueue_unique( self::HOOK_POST, array( (int) $post_id ) ); } } /** * Enqueue menu re-extraction. */ public function on_menu_change(): void { Jobs::enqueue_unique( self::HOOK_MENUS ); } /** * Enqueue widget re-extraction. */ public function on_widgets_change(): void { Jobs::enqueue_unique( self::HOOK_WIDGETS ); } /** * Enqueue comment re-extraction (only when comment scanning is enabled). * * @param int $comment_id Comment ID. */ public function on_comment_change( $comment_id ): void { if ( Settings::source_enabled( 'comment' ) ) { Jobs::enqueue_unique( self::HOOK_COMMENT, array( (int) $comment_id ) ); } } /** * Job: re-extract one post. * * @param int $post_id Post ID. */ public function handle_post( $post_id ): void { $this->indexer->index_post( (int) $post_id ); } /** * Job: re-extract all menus. */ public function handle_menus(): void { $this->indexer->index_menus(); } /** * Job: re-extract all widgets. */ public function handle_widgets(): void { $this->indexer->index_widgets(); } /** * Job: re-extract one comment. * * @param int $comment_id Comment ID. */ public function handle_comment( $comment_id ): void { $this->indexer->index_comment( (int) $comment_id ); } }