diff --git a/README.md b/README.md index cb0cfc61..22f336a9 100644 --- a/README.md +++ b/README.md @@ -94,3 +94,19 @@ add_filter( 'msm_sitemap_index', function( $sitemaps ) { } ); } ); ``` + +## Filter Sitemap Index + +Use the `msm_pre_get_last_modified_posts` filter to customize the query that gets the last modified posts. + +On large sites, this filter could be leveraged to enhance query efficiency by avoiding scanning older posts that don't get updated frequently and making better use of the `type_status_date` index. + +``` +function ( $query, $post_types_in, $date ) { + global $wpdb; + + $query = $wpdb->prepare( "SELECT ID, post_date FROM $wpdb->posts WHERE post_type IN ( {$post_types_in} ) AND post_status = 'publish' AND post_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH) AND post_modified_gmt >= %s LIMIT 1000", $date ); + + return $query; +}; +``` diff --git a/msm-sitemap.php b/msm-sitemap.php index 319ce70d..b82f8274 100644 --- a/msm-sitemap.php +++ b/msm-sitemap.php @@ -615,7 +615,20 @@ public static function get_last_modified_posts() { $post_types_in = self::get_supported_post_types_in(); - $modified_posts = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_date FROM $wpdb->posts WHERE post_type IN ( {$post_types_in} ) AND post_modified_gmt >= %s LIMIT 1000", $date ) ); + $query = $wpdb->prepare( "SELECT ID, post_date FROM $wpdb->posts WHERE post_type IN ( {$post_types_in} ) AND post_modified_gmt >= %s LIMIT 1000", $date ); + + /** + * Filter the query used to get the last modified posts. + * $wpdb->prepare() should be used for security if a new replacement query is created in the callback. + * + * @param string $query The query to use to get the last modified posts. + * @param string $post_types_in A comma-separated list of post types to include in the query. + * @param string $date The date to use as the cutoff for the query. + */ + $query = apply_filters( 'msm_pre_get_last_modified_posts', $query, $post_types_in, $date ); + + $modified_posts = $wpdb->get_results( $query ); + return $modified_posts; } diff --git a/tests/test-sitemap-functions.php b/tests/test-sitemap-functions.php index 590928a5..0a69f67d 100644 --- a/tests/test-sitemap-functions.php +++ b/tests/test-sitemap-functions.php @@ -424,4 +424,48 @@ function add_post_status_to_msm_sitemap( $post_status ) { return 'live'; } + function test_get_last_modified_posts_filter_no_change() { + $posts_before = Metro_Sitemap::get_last_modified_posts(); + $tag = 'msm_pre_get_last_modified_posts'; + + // Test no changes to query. + $function = function ( $query ) { + return $query; + }; + add_filter( $tag, $function, 10, 3 ); + $posts_after = Metro_Sitemap::get_last_modified_posts(); + remove_filter( $tag, $function ); + + $this->assertEquals( count( $posts_before ), count( $posts_after ) ); + } + + function test_get_last_modified_posts_filter_change_query() { + $posts_before = Metro_Sitemap::get_last_modified_posts(); + $tag = 'msm_pre_get_last_modified_posts'; + + // Modify query to fetch posts created in the last 3 months. + $function = function ( $query, $post_types_in, $date ) { + global $wpdb; + $query = $wpdb->prepare( "SELECT ID, post_date FROM $wpdb->posts WHERE post_type IN ( {$post_types_in} ) AND post_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH) AND post_modified_gmt >= %s LIMIT 1000", $date ); + return $query; + }; + + add_filter( $tag, $function, 10, 3 ); + $posts_after_date = Metro_Sitemap::get_last_modified_posts(); + remove_filter( $tag, $function ); + + // Modify query as string to fetch only 10 posts. + $limit = 10; + $function = function ( $query ) use ( $limit ) { + return str_replace( 'LIMIT 1000', "LIMIT $limit", $query ); + }; + + add_filter( $tag, $function ); + $posts_after = Metro_Sitemap::get_last_modified_posts(); + remove_filter( $tag, $function ); + + $this->assertLessThan( count( $posts_before ), count( $posts_after_date ) ); + $this->assertEquals( count( $posts_after ), $limit ); + } + }