Replace all your above code with the one below:
<?php
function master_load_ads_txt_template_include( $template ) {
$is_load_ads_txt = (bool) get_query_var( 'ads-txt' );
if ( $is_load_ads_txt ) {
$template = locate_template( 'template-parts/ads-txt.php' );
}
return $template;
}
add_filter( 'template_include', 'master_load_ads_txt_template_include' );
function master_load_ads_txt_rewrite() {
add_rewrite_rule( 'ads.txt', 'index.php?ads-txt=true', 'top' );
// The line below doesn't work and it's useless.
// add_rewrite_rule( '^ads.txt/', 'ads.txt', 'top' );
}
add_action( 'init', 'master_load_ads_txt_rewrite' );
function master_load_ads_txt_query_vars( $query_vars ) {
$query_vars[] = 'ads-txt';
return $query_vars;
}
add_filter( 'query_vars', 'master_load_ads_txt_query_vars' );
function redirect_canonical_callback( $redirect_url, $requested_url ) {
$is_load_ads_txt = (bool) get_query_var( 'ads-txt' );
if ( $is_load_ads_txt ) {
return $requested_url;
}
return $redirect_url;
}
add_filter( 'redirect_canonical', 'redirect_canonical_callback', 100, 2 );
A few notes:
template_include
is a filter hook, not an action hook. It’s fixed.- As pointed in the comments your rule
add_rewrite_rule('^ads.txt/', 'ads.txt', 'top');
is useless. It’s fixed. - In this case,
redirect_canonical
should be used within a filter hook, not an action. - After putting the code above in your functions.php file don’t forget to flush your permalinks by visiting Settings > Permalinks.