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; } }