settings = $settings; $this->logger = $logger; } /** * Register hooks. * * @return void */ public function register() { add_action( 'acelora_site_accelerator_preload_batch', array( $this, 'process_batch' ) ); } /** * Start URL warmup. * * @param bool $manual Whether manually triggered. * @return array */ public function start( $manual = true ) { if ( ! $this->settings->get( 'preload.enabled', 1 ) ) { return $this->status(); } $urls = $this->collect_urls(); update_option( self::QUEUE_OPTION, $urls, false ); update_option( self::STATUS_OPTION, array( 'state' => 'queued', 'total' => count( $urls ), 'processed' => 0, 'failed' => 0, 'last_url' => '', 'manual' => (bool) $manual, 'started_at' => current_time( 'mysql' ), ), false ); if ( ! wp_next_scheduled( 'acelora_site_accelerator_preload_batch' ) ) { wp_schedule_single_event( time() + 5, 'acelora_site_accelerator_preload_batch' ); } $this->logger->log( 'info', 'Preload queued.', array( 'total' => count( $urls ) ) ); return $this->status(); } /** * Process preload batch. * * @return void */ public function process_batch() { $queue = get_option( self::QUEUE_OPTION, array() ); $status = $this->status(); $batch_size = max( 1, absint( $this->settings->get( 'preload.batch_size', 8 ) ) ); if ( empty( $queue ) ) { $status['state'] = 'complete'; $status['finished_at'] = current_time( 'mysql' ); update_option( self::STATUS_OPTION, $status, false ); return; } $status['state'] = 'running'; $batch = array_splice( $queue, 0, $batch_size ); foreach ( $batch as $url ) { $response = wp_remote_get( $url, array( 'timeout' => 10, 'redirection' => 2, 'headers' => array( 'X-Acelora-Preload' => '1' ), 'user-agent' => 'Acelora Site Accelerator/' . ACELORA_SITE_ACCELERATOR_VERSION, ) ); $status['last_url'] = $url; $status['processed']++; if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 400 ) { $status['failed']++; } } update_option( self::QUEUE_OPTION, $queue, false ); if ( empty( $queue ) ) { $status['state'] = 'complete'; $status['finished_at'] = current_time( 'mysql' ); } else { wp_schedule_single_event( time() + 5, 'acelora_site_accelerator_preload_batch' ); } update_option( self::STATUS_OPTION, $status, false ); $this->logger->log( 'info', 'Preload batch processed.', $status ); } /** * Current preload status. * * @return array */ public function status() { return wp_parse_args( get_option( self::STATUS_OPTION, array() ), array( 'state' => 'idle', 'total' => 0, 'processed' => 0, 'failed' => 0, 'last_url' => '', ) ); } /** * Collect preload URLs. * * @return array */ private function collect_urls() { $urls = array( home_url( '/' ) ); foreach ( $this->sitemap_locations() as $sitemap_url ) { $response = wp_remote_get( $sitemap_url, array( 'timeout' => 8 ) ); if ( is_wp_error( $response ) ) { continue; } preg_match_all( '#\s*([^<]+)\s*#i', wp_remote_retrieve_body( $response ), $matches ); if ( ! empty( $matches[1] ) ) { $urls = array_merge( $urls, array_map( 'esc_url_raw', $matches[1] ) ); } } $post_types = get_post_types( array( 'public' => true ), 'names' ); $posts = get_posts( array( 'post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => 250, 'fields' => 'ids', 'orderby' => 'modified', 'order' => 'DESC', 'no_found_rows' => true, ) ); foreach ( $posts as $post_id ) { $urls[] = get_permalink( $post_id ); } $taxonomies = get_taxonomies( array( 'public' => true ), 'names' ); $terms = get_terms( array( 'taxonomy' => $taxonomies, 'hide_empty' => true, 'number' => 100, ) ); if ( ! is_wp_error( $terms ) ) { foreach ( $terms as $term ) { $urls[] = get_term_link( $term ); } } $urls = array_filter( array_map( 'esc_url_raw', $urls ) ); return array_values( array_unique( $urls ) ); } /** * Sitemap locations. * * @return array */ private function sitemap_locations() { $manual = $this->settings->list_value( $this->settings->get( 'preload.sitemap_urls', '' ) ); if ( empty( $manual ) ) { $manual = array( home_url( '/wp-sitemap.xml' ) ); } return $manual; } }