render(); header( 'Content-Type: application/xml; charset=UTF-8' ); header( 'X-Robots-Tag: noindex, follow', true ); echo $xml; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render() escapes every value it writes and the result is a complete XML document. exit; } /** * Print the sitemap discovery link in . * * @return void */ public function output_discovery_tag() { if ( ! ACSSEO_Settings::get( 'sitemap_enabled' ) ) { return; } if ( ! is_front_page() && ! is_home() ) { return; } printf( '' . "\n", esc_attr__( 'Sitemap', 'acs-seo-plus' ), esc_url( self::url() ) ); } /** * Build the sitemap, using a one hour cache. * * @return string */ public function render() { $cached = get_transient( self::CACHE_KEY ); if ( is_string( $cached ) && '' !== $cached ) { return $cached; } $post_types = (array) ACSSEO_Settings::get( 'sitemap_post_types', array( 'post', 'page' ) ); $allowed = array_keys( ACSSEO_Settings::selectable_post_types() ); $post_types = array_values( array_intersect( $post_types, $allowed ) ); $lines = array(); $lines[] = ''; $lines[] = ''; $lines[] = "\t"; $lines[] = "\t\t" . esc_url( home_url( '/' ) ) . ''; $lines[] = "\t\tdaily"; $lines[] = "\t\t1.0"; $lines[] = "\t"; if ( ! empty( $post_types ) ) { $query = new WP_Query( array( 'post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => 2000, 'orderby' => 'modified', 'order' => 'DESC', 'ignore_sticky_posts' => true, 'no_found_rows' => true, 'update_post_term_cache' => false, 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- the result is cached for an hour and the sitemap has to skip entries the author marked noindex. 'relation' => 'OR', array( 'key' => '_acsseo_noindex', 'compare' => 'NOT EXISTS', ), array( 'key' => '_acsseo_noindex', 'value' => '1', 'compare' => '!=', ), ), ) ); $front_page_id = ( 'page' === get_option( 'show_on_front' ) ) ? (int) get_option( 'page_on_front' ) : 0; foreach ( $query->posts as $post ) { // The home address is already listed first, so a static front // page is not listed a second time. if ( $front_page_id && (int) $post->ID === $front_page_id ) { continue; } $permalink = get_permalink( $post ); if ( ! $permalink ) { continue; } $modified = get_post_modified_time( DATE_W3C, true, $post ); $lines[] = "\t"; $lines[] = "\t\t" . esc_url( $permalink ) . ''; if ( $modified ) { $lines[] = "\t\t" . esc_html( $modified ) . ''; } $lines[] = "\t\t" . esc_html( $this->changefreq_for( $post ) ) . ''; $lines[] = "\t\t" . esc_html( $this->priority_for( $post ) ) . ''; $lines[] = "\t"; } wp_reset_postdata(); } $lines[] = ''; $xml = implode( "\n", $lines ) . "\n"; set_transient( self::CACHE_KEY, $xml, HOUR_IN_SECONDS ); return $xml; } /** * Suggested crawl frequency, based on how recent the entry is. * * @param WP_Post $post Post object. * @return string */ private function changefreq_for( $post ) { $age_in_days = ( time() - (int) get_post_time( 'U', true, $post ) ) / DAY_IN_SECONDS; return $age_in_days < 180 ? 'weekly' : 'monthly'; } /** * Suggested priority, based on how recent the entry is. * * @param WP_Post $post Post object. * @return string */ private function priority_for( $post ) { $age_in_days = ( time() - (int) get_post_time( 'U', true, $post ) ) / DAY_IN_SECONDS; if ( $age_in_days < 30 ) { return '0.9'; } if ( $age_in_days < 180 ) { return '0.8'; } return '0.7'; } /** * Drop the cached sitemap. * * @return void */ public function clear_cache() { delete_transient( self::CACHE_KEY ); } }