settings = new XML_Sitemap_Settings( $this->options );
$this->metabox = new XML_Sitemap_Metaboxes( $this->options );
add_filter( 'wp_sitemaps_post_types', [ $this, 'edit_sitemap_post_types' ] );
add_filter( 'wp_sitemaps_taxonomies', [ $this, 'edit_sitemap_taxonomies' ] );
add_filter( 'wp_sitemaps_add_provider', [ $this, 'maybe_add_sitemap_users' ], 10, 2 );
add_filter( 'wp_sitemaps_register_providers', [ $this, 'maybe_register_users' ] );
add_filter( 'wp_sitemaps_posts_query_args', [ $this, 'edit_sitemap_posts_query_args' ] );
add_filter( 'wp_sitemaps_taxonomies_query_args', [ $this, 'edit_sitemap_categories_query_args' ], 10, 2 );
add_filter( 'wp_sitemaps_max_urls', [ $this, 'change_sitemap_max_urls_count' ] );
add_filter( 'wp_sitemaps_index_entry', [ $this, 'add_sitemap_index_lastmod' ], 10, 3 );
add_filter( 'wp_sitemaps_taxonomies_entry', [ $this, 'add_taxonomies_sitemap_lastmod' ], 10, 3 );
add_filter( 'wp_sitemaps_users_entry', [ $this, 'add_users_sitemap_lastmod' ], 10, 2 );
if ( ! empty( $this->options['include_in_robotstxt'] ) ) {
add_filter( 'robots_txt', [ $this, 'add_sitemap_link_robotstxt' ], 1000000, 1 );
}
if ( ! empty( $this->options['custom_sitemap_slug'] ) ) {
add_action( 'init', [ $this, 'rewrite_sitemap_url' ] );
add_filter( 'home_url', [ $this, 'fix_wp_sitemap_url' ], 11, 2 );
}
add_filter(
'adminoptim_notification_message_' . self::MODULE_SLUG,
static function ( $message, $display ) {
if ( 'banner' === $display ) {
return sprintf(
/* translators: 1: Opening strong tag, 2: Closing strong tag. */
__(
'%1$sGenerating XML sitemaps effortlessly?%2$s Leave a ★★★★★ review and help more users discover Admin Optimizer.',
'admin-optimizer'
),
'',
''
);
} else {
return sprintf(
/* translators: 1: Opening strong tag, 2: Closing strong tag. */
__(
'%1$sUsing XML sitemaps?%2$s Unlock advanced sitemap controls, News Sitemaps, and more with Admin Optimizer Pro.',
'admin-optimizer'
),
'',
''
);
}
},
10,
2
);
}
/**
* Return the module's submenu definition.
*
* @return array
*/
protected function get_submenu_config(): array {
return [
'page_title' => __( 'XML Sitemap', 'admin-optimizer' ),
'menu_title' => __( 'XML Sitemap', 'admin-optimizer' ),
'menu_slug' => self::MENU_SLUG,
'callback' => [ $this->settings, 'render_settings_page' ],
];
}
/**
* Edit sitemap post types
*
* @return array
*/
public function edit_sitemap_post_types() {
$post_types = [];
if ( ! empty( $this->options['post_types'] ) ) {
foreach ( $this->options['post_types'] as $post_type ) {
$post_types[ $post_type ] = get_post_type_object( $post_type );
}
} else {
$post_types = [ 'post' => get_post_type_object( 'post' ) ];
}
return $post_types;
}
/**
* Edit sitemap taxonomies
*
* @return array
*/
public function edit_sitemap_taxonomies() {
$taxonomies = [];
if ( ! empty( $this->options['taxonomies'] ) ) {
foreach ( $this->options['taxonomies'] as $taxonomy ) {
$taxonomies[ $taxonomy ] = get_taxonomy( $taxonomy );
}
}
return $taxonomies;
}
/**
* Maybe disable user entries from showing up in sitemap
*
* @param \WP_Sitemaps_Provider $provider Sitemap provider.
* @param string $name Name of provider.
* @return bool|void
*/
public function maybe_add_sitemap_users( $provider, $name ) {
if ( empty( $this->options['include_authors'] ) && 'users' === $name ) {
return false;
}
return $provider;
}
/**
* Maybe disable user from registered in Sitemap provider
*
* @param \WP_Sitemaps_Provider $providers Sitemap provider.
* @return \WP_Sitemaps_Provider
*/
public function maybe_register_users( $providers ) {
if ( empty( $this->options['include_authors'] ) ) {
unset( $providers['users'] );
}
return $providers;
}
/**
* Filter the sitemap max urls count
*
* @param int $count Urls count.
* @return int
*/
public function change_sitemap_max_urls_count( $count ) {
if ( ! empty( $this->options['max_entries'] ) ) {
return absint( $this->options['max_entries'] );
} else {
return $count;
}
}
/**
* Edit Sitemap query args
*
* @param array $args Post arguments.
* @return array
*/
public function edit_sitemap_posts_query_args( $args ) {
$meta_query = isset( $args['meta_query'] ) && is_array( $args['meta_query'] ) ? $args['meta_query'] : [];
$meta_query[] = [
'key' => '_adminoptim_xml_exclude',
'compare' => 'NOT EXISTS',
];
$args['meta_query'] = $meta_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
$args['orderby'] = 'modified';
$args['order'] = 'DESC';
return $args;
}
/**
* Exclude selected categories from the sitemap
*
* @param [] $args Args of the query.
* @param string $taxonomy Taxonomy of the query.
* @return []
*/
public function edit_sitemap_categories_query_args( $args, $taxonomy ) {
if ( 'category' !== $taxonomy ) {
return $args;
}
if ( ! empty( $this->options['exclude_categories'] ) && is_array( $this->options['exclude_categories'] ) ) {
$args['exclude'] = $this->options['exclude_categories']; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude
}
return $args;
}
/**
* Add last modified date to sitemap index entries
*
* @param array $entry Sitemap entry.
* @param string $object_type Object type.
* @param string $object_subtype Object subtype.
* @return array
*/
public function add_sitemap_index_lastmod( $entry, $object_type, $object_subtype ) {
// Skip if lastmod already exists.
if ( ! empty( $entry['lastmod'] ) ) {
return $entry;
}
$modified_time = '';
if ( 'post' === $object_type ) {
$args = [
'post_type' => $object_subtype,
'posts_per_page' => 1,
'orderby' => 'modified',
'order' => 'DESC',
'post_status' => 'publish',
'fields' => 'ids',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
];
$latest_post = get_posts( $args );
if ( ! empty( $latest_post ) ) {
$modified_time = get_post_modified_time( DATE_W3C, true, $latest_post[0] );
}
} elseif ( 'term' === $object_type ) {
$args = [
'post_type' => 'any',
'posts_per_page' => 1,
'orderby' => 'modified',
'order' => 'DESC',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
[
'taxonomy' => $object_subtype,
'operator' => 'EXISTS',
],
],
'no_found_rows' => true,
'ignore_sticky_posts' => true,
];
$latest_post = get_posts( $args );
if ( ! empty( $latest_post ) ) {
$modified_time = get_post_modified_time( DATE_W3C, true, $latest_post[0] );
}
} elseif ( 'user' === $object_type ) {
$args = [
'post_type' => 'any',
'posts_per_page' => 1,
'orderby' => 'modified',
'order' => 'DESC',
'post_status' => 'publish',
'fields' => 'ids',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
];
$latest_post = get_posts( $args );
if ( ! empty( $latest_post ) ) {
$modified_time = get_post_modified_time( DATE_W3C, true, $latest_post[0] );
}
}
if ( ! empty( $modified_time ) ) {
$entry['lastmod'] = $modified_time;
}
return $entry;
}
/**
* Add last modified date to taxonomy sitemap entries
*
* @param array $sitemap_entry Sitemap entry.
* @param int $term_id Term ID.
* @param string $taxonomy Taxonomy name.
* @return array
*/
public function add_taxonomies_sitemap_lastmod( $sitemap_entry, $term_id, $taxonomy ) {
$args = [
'post_type' => 'any',
'posts_per_page' => 1,
'orderby' => 'modified',
'order' => 'DESC',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
[
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $term_id,
],
],
'no_found_rows' => true,
'ignore_sticky_posts' => true,
];
$latest_post = get_posts( $args );
if ( ! empty( $latest_post ) ) {
$sitemap_entry['lastmod'] = get_post_modified_time( DATE_W3C, true, $latest_post[0] );
}
return $sitemap_entry;
}
/**
* Add last modified date to user sitemap entries
*
* @param array $sitemap_entry Sitemap entry.
* @param \WP_User $user User object.
* @return array
*/
public function add_users_sitemap_lastmod( $sitemap_entry, $user ) {
$args = [
'post_type' => 'any',
'posts_per_page' => 1,
'orderby' => 'modified',
'order' => 'DESC',
'post_status' => 'publish',
'author' => $user->ID,
'fields' => 'ids',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
];
$latest_post = get_posts( $args );
if ( ! empty( $latest_post ) ) {
$sitemap_entry['lastmod'] = get_post_modified_time( DATE_W3C, true, $latest_post[0] );
}
return $sitemap_entry;
}
/**
* Add sitemap link to robots.txt
*
* @param string $output robots.txt content.
* @return string robots.txt content
*/
public function add_sitemap_link_robotstxt( $output ) {
if ( ! empty( $this->options['include_in_robotstxt'] ) && ! str_contains( $output, '# BEGIN XML-SITEMAP LINK' ) ) {
$output .= "\n\n# BEGIN XML-SITEMAP LINK\n";
$sitemap_url = apply_filters( 'adminoptimizer_sitemap_url', $this->get_sitemap_url() );
$output .= 'Sitemap: ' . esc_url( $sitemap_url ) . "\n";
$output .= '# END XML-SITEMAP LINK';
}
return $output;
}
/**
* Get sitemap url
*
* @return string
*/
private function get_sitemap_url() {
if ( ! empty( $this->options['custom_sitemap_slug'] ) ) {
return home_url( '/' . $this->options['custom_sitemap_slug'] . '.xml' );
} else {
return home_url( 'wp-sitemap.xml' );
}
}
/**
* Rewrite sitemap url
*
* @return void
*/
public function rewrite_sitemap_url() {
add_rewrite_rule( "^{$this->options['custom_sitemap_slug']}\.xml$", 'index.php?sitemap=index', 'top' );
if ( empty( $this->options['flushed_rules'] ) ) {
flush_rewrite_rules();
$this->options['flushed_rules'] = 1;
update_option( self::OPTION_NAME, $this->options );
}
}
/**
* Replaces the url from wp-sitemap.xml to sitemap.xml
*
* @param string $url Url of the sitemap.
* @param string $path Url path of the sitemap.
* @return string
*/
public function fix_wp_sitemap_url( $url, $path ) {
if ( '/wp-sitemap.xml' === $path ) {
$slug = $this->options['custom_sitemap_slug'];
return str_replace( '/wp-sitemap.xml', "/{$slug}.xml", $url );
}
return $url;
}
}