Source: classes/Sitemap.php

<?php
/**
 * Sitemap class
 *
 * @package simple-google-news-sitemap
 */

namespace SimpleGoogleNewsSitemap;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Represents the entire sitemap
 */
class Sitemap {

	/**
	 * News items to be included in the sitemap.
	 *
	 * @var array
	 */
	private $data = [];

	/**
	 * Range of news items to include in the sitemap e.g. 2 days.
	 *
	 * @var int
	 */
	private $range = 2;

	/**
	 * Support post types.
	 *
	 * @var array
	 */
	private $post_types = [];

	/**
	 * Items to process in each DB cycle.
	 *
	 * @var int
	 */
	private $process_page_size = 500;

	/**
	 * Create a new empty sitemap.
	 */
	public function __construct() {
		$this->range      = date( 'Y-m-d H:i:s', strtotime( '-' . (int) $this->range . ' day' ) ); // phpcs:ignore
		$this->post_types = $this->supported_post_types();
	}

	/**
	 * Retrieve supported post types.
	 *
	 * @return array
	 */
	public function supported_post_types(): array {
		$post_types = array_filter( get_post_types(), 'is_post_type_viewable' );

		$exclude_post_types = [
			'attachment',
			'redirect_rule',
		];

		foreach ( $exclude_post_types as $exclude_post_type ) {
			unset( $post_types[ $exclude_post_type ] );
		}

		/**
		 * Filter the list of supported post types.
		 *
		 * @since 1.0.0
		 *
		 * @hook simple_google_news_sitemap_post_types
		 * @param {array} $post_types List of post types to support.
		 * @returns {array} List of post types to support.
		 */
		return apply_filters( 'simple_google_news_sitemap_post_types', $post_types );
	}

	/**
	 * Build news items sitemap.
	 *
	 * @return void
	 */
	public function build() {
		global $wpdb;

		foreach ( $this->post_types as $post_type ) {
			$offset = 0;

			while ( true ) {
				$results = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_title, post_date FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = %s AND post_date >= %s ORDER BY post_date DESC LIMIT %d, %d", $post_type, $this->range, (int) $offset, (int) $this->process_page_size ), ARRAY_A );

				if ( empty( $results ) ) {
					break;
				}

				foreach ( $results as $result ) {
					$permalink = get_permalink( $result['ID'] );

					$item = [
						'ID'       => (int) $result['ID'],
						'url'      => $permalink,
						'title'    => $result['post_title'],
						'modified' => strtotime( $result['post_date'] ),
					];

					/**
					 * Filter an individual item before it goes to the sitemap.
					 *
					 * This can be used to modify a specific item or remove an
					 * item all together.
					 *
					 * @since 1.0.0
					 *
					 * @hook simple_google_news_sitemap_post
					 * @param {array}  $item The item that will be displayed.
					 * @param {string} $post_type The post type of the item.
					 * @returns {array} The item that will be displayed.
					 */
					$item = apply_filters( 'simple_google_news_sitemap_post', $item, $post_type );

					if ( ! empty( $item ) && ! empty( $item['url'] ) ) {
						$this->data[] = $item;
					}

					$this->stop_the_insanity();
				}

				$offset += $this->process_page_size;
			}
		}

		// Add sitemap data to cache (if available) or wp_options.
		CacheUtils::set_cache( $this->data );
	}

	/**
	 * Get data range.
	 *
	 * @return string
	 */
	public function get_range(): string {
		return $this->range;
	}

	/**
	 * Get sitemap data.
	 *
	 * @return array
	 */
	public function get_data(): array {
		return $this->data;
	}

	/**
	 * Get post types.
	 *
	 * @return array
	 */
	public function get_post_types(): array {
		return $this->post_types;
	}

	/**
	 * Clear all of the caches for memory management.
	 *
	 * @return void
	 */
	private function stop_the_insanity() {
		global $wpdb, $wp_object_cache;

		$one_hundred_mb = 104857600;
		if ( memory_get_usage() <= $one_hundred_mb ) {
			return;
		}

		$wpdb->queries = array();

		if ( is_object( $wp_object_cache ) ) {
			$wp_object_cache->group_ops      = array();
			$wp_object_cache->stats          = array();
			$wp_object_cache->memcache_debug = array();
			$wp_object_cache->cache          = array();

			if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
				$wp_object_cache->__remoteset(); // important
			}
		}

		gc_collect_cycles();
	}
}