prefix . 'aidf_crawler_log'; $status_code = 200; $now = current_time( 'mysql', true ); $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $table, array( 'bot_name' => $all_bots[ $matched_key ]['name'], 'bot_ua' => mb_substr( $ua, 0, 500 ), 'url_path' => mb_substr( $url_path, 0, 500 ), 'status_code' => $status_code, 'created_at' => $now, ), array( '%s', '%s', '%s', '%d', '%s' ) ); /** * Fires after a crawler hit has been written to the log. * * @since 1.3.0 * * @param string $bot_name Human-readable bot name. * @param string $url_path Requested URL path (e.g. /llms.txt). * @param int $status_code HTTP response status code (always 200). */ do_action( 'aidf_crawler_hit_logged', $all_bots[ $matched_key ]['name'], $url_path, $status_code ); } /** * Schedule the daily cron events used by the crawler analytics feature. * * Should be called when crawler logging is enabled (e.g. on settings * save). Uses `wp_next_scheduled` guards so calling it multiple times * is safe. * * @since 1.3.0 * @return void */ public static function schedule_cron() { if ( ! wp_next_scheduled( 'aidf_rebuild_crawler_summary' ) ) { wp_schedule_event( time(), 'daily', 'aidf_rebuild_crawler_summary' ); } if ( ! wp_next_scheduled( 'aidf_prune_crawler_log' ) ) { wp_schedule_event( time(), 'daily', 'aidf_prune_crawler_log' ); } } /** * Remove the daily cron events registered by this logger. * * Called on plugin deactivation or when logging is disabled in settings * so no orphaned cron events remain in the scheduler. * * @since 1.3.0 * @return void */ public static function clear_cron() { wp_clear_scheduled_hook( 'aidf_rebuild_crawler_summary' ); wp_clear_scheduled_hook( 'aidf_prune_crawler_log' ); } /** * Delete log rows that fall outside the configured retention window. * * Called daily via the `aidf_prune_crawler_log` cron event. Removes * entries from both the raw log table and the pre-aggregated summary * table that are older than the `crawler_log_retention` setting (days). * Defaults to 90 days if the setting is below 30. * * @since 1.3.0 * @return void */ public static function prune_log() { global $wpdb; $settings = AIDF_Plugin::get_settings(); $retention = absint( $settings['crawler_log_retention'] ); if ( $retention < 30 ) { $retention = 30; } $cutoff = gmdate( 'Y-m-d H:i:s', strtotime( "-{$retention} days" ) ); $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( "DELETE FROM {$wpdb->prefix}aidf_crawler_log WHERE created_at < %s", $cutoff ) ); $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( "DELETE FROM {$wpdb->prefix}aidf_crawler_summary WHERE log_date < %s", gmdate( 'Y-m-d', strtotime( "-{$retention} days" ) ) ) ); } }