sitemap->type, [ 'general', 'rss' ], true ) || ! $this->isEnabled() ) { return []; } switch ( aioseo()->sitemap->indexName ) { case 'rss': return $this->rss(); case 'root': if ( 'root' === aioseo()->sitemap->indexName && aioseo()->options->sitemap->general->indexes ) { return aioseo()->sitemap->root->indexes(); } // If indexes are disabled, throw all entries together into one big file. return $this->nonIndexed(); default: // Check if requested index has a dedicated method. $methodName = aioseo()->helpers->dashesToCamelCase( aioseo()->sitemap->indexName ); if ( method_exists( $this, $methodName ) ) { return $this->$methodName(); } // Check if requested index is a registered post type. if ( in_array( aioseo()->sitemap->indexName, aioseo()->sitemap->helpers->includedPostTypes(), true ) ) { return $this->posts( aioseo()->sitemap->indexName ); } // Check if requested index is a registered taxonomy. if ( in_array( aioseo()->sitemap->indexName, aioseo()->sitemap->helpers->includedTaxonomies(), true ) ) { return $this->terms( aioseo()->sitemap->indexName ); } return []; } return []; } /** * Returns the total entries number for the requested sitemap. * * @since 4.1.5 * * @return int The total entries number. */ public function getTotal() { if ( ! in_array( aioseo()->sitemap->type, [ 'general', 'rss' ], true ) || ! $this->isEnabled() ) { return 0; } switch ( aioseo()->sitemap->indexName ) { case 'rss': return count( $this->rss() ); case 'root': if ( 'root' === aioseo()->sitemap->indexName && aioseo()->options->sitemap->general->indexes ) { return count( aioseo()->sitemap->root->indexes() ); } return count( $this->nonIndexed() ); default: // Check if requested index has a dedicated method. $methodName = aioseo()->helpers->dashesToCamelCase( aioseo()->sitemap->indexName ); if ( method_exists( $this, $methodName ) ) { return count( $this->$methodName() ); } // Check if requested index is a registered post type. if ( in_array( aioseo()->sitemap->indexName, aioseo()->sitemap->helpers->includedPostTypes(), true ) ) { return aioseo()->sitemap->query->posts( aioseo()->sitemap->indexName, [ 'count' => true ] ); } // Check if requested index is a registered taxonomy. if ( in_array( aioseo()->sitemap->indexName, aioseo()->sitemap->helpers->includedTaxonomies(), true ) ) { return aioseo()->sitemap->query->terms( aioseo()->sitemap->indexName, [ 'count' => true ] ); } } return 0; } /** * Checks if the requested sitemap is enabled. * * @since 4.0.0 * * @return boolean Whether the sitemap is enabled. */ public function isEnabled() { $options = aioseo()->options->noConflict(); if ( ! $options->sitemap->{aioseo()->sitemap->type}->enable ) { return false; } if ( 'general' === aioseo()->sitemap->type ) { return true; } if ( $options->sitemap->{aioseo()->sitemap->type}->has( 'indexes' ) && ! $options->sitemap->{aioseo()->sitemap->type}->indexes && 'root' !== aioseo()->sitemap->indexName ) { return false; } if ( $options->sitemap->{aioseo()->sitemap->type}->postTypes->all ) { return true; } $included = aioseo()->sitemap->helpers->includedPostTypes(); return ! empty( $included ); } /** * Returns all sitemap entries if indexing is disabled. * * @since 4.0.0 * * @return array $entries The sitemap entries. */ private function nonIndexed() { $entries = array_merge( $this->addl(), $this->author(), $this->date(), $this->postArchive() ); $postTypes = aioseo()->sitemap->helpers->includedPostTypes(); if ( $postTypes ) { foreach ( $postTypes as $postType ) { $entries = array_merge( $entries, $this->posts( $postType ) ); } } $taxonomies = aioseo()->sitemap->helpers->includedTaxonomies(); if ( $taxonomies ) { foreach ( $taxonomies as $taxonomy ) { $entries = array_merge( $entries, $this->terms( $taxonomy ) ); } } return $entries; } /** * Returns all post entries for a given post type. * * @since 4.0.0 * * @param string $postType The name of the post type. * @param array $additionalArgs Any additional arguments for the post query. * @return array The sitemap entries. */ public function posts( $postType, $additionalArgs = [] ) { $posts = aioseo()->sitemap->query->posts( $postType, $additionalArgs ); if ( ! $posts ) { return []; } // Return if we're determining the root indexes. if ( ! empty( $additionalArgs['root'] ) && $additionalArgs['root'] ) { return $posts; } $entries = []; $isStaticHomepage = 'page' === get_option( 'show_on_front' ); $homePageId = (int) get_option( 'page_on_front' ); $excludeImages = aioseo()->options->sitemap->general->advancedSettings->enable && aioseo()->options->sitemap->general->advancedSettings->excludeImages; foreach ( $posts as $post ) { $entry = [ 'loc' => get_permalink( $post->ID ), 'lastmod' => aioseo()->helpers->dateTimeToIso8601( $post->post_modified_gmt ), 'changefreq' => aioseo()->sitemap->priority->frequency( 'postTypes', $post, $postType ), 'priority' => aioseo()->sitemap->priority->priority( 'postTypes', $post, $postType ), ]; if ( ! $excludeImages ) { $metaData = aioseo()->meta->metaData->getMetaData( $post->ID ); $entry['images'] = ! empty( $metaData->images ) ? $metaData->images : []; } // Override priority/frequency for static homepage. if ( $isStaticHomepage && $homePageId === $post->ID ) { $entry['loc'] = aioseo()->helpers->maybeRemoveTrailingSlash( $entry['loc'] ); $entry['changefreq'] = aioseo()->sitemap->priority->frequency( 'homePage' ); $entry['priority'] = aioseo()->sitemap->priority->priority( 'homePage' ); } $entry = $this->localizeEntries( $entry, $post, $postType ); if ( $entry ) { $entries[] = $entry; } } return apply_filters( 'aioseo_sitemap_posts', $entries, $postType ); } /** * Localize the entries if WPML (or others in the future) are active. * * @since 4.0.0 * * @param array $entry The entry. * @param WP_Post $post The post object. * @param string $postType The post type. * @param boolean $rss Whether or not we are localizing for the RSS sitemap. * @return array The entry. */ private function localizeEntries( $entry, $post, $postType, $rss = false ) { if ( null === self::$wpml ) { self::$wpml = false; if ( aioseo()->helpers->isWpmlActive() ) { self::$wpml = apply_filters( 'wpml_default_language', null ); } } if ( ! self::$wpml ) { return $entry; } static $activeLanguages = null; if ( null === $activeLanguages ) { $activeLanguages = apply_filters( 'wpml_active_languages', null ); } $parentId = apply_filters( 'wpml_object_id', $post->ID, $postType, false, self::$wpml ); if ( ! empty( $parentId ) && $parentId !== $post->ID && ! $rss ) { // Skip adding a translation to the entries. return null; } $translationGroupId = apply_filters( 'wpml_element_trid', null, $post->ID ); $translations = apply_filters( 'wpml_get_element_translations', null, $translationGroupId, $postType ); if ( empty( $translations ) ) { return $entry; } $entry['languages'] = []; foreach ( $translations as $translation ) { if ( empty( $translation->element_id ) ) { continue; } $permalink = ! empty( $entry['loc'] ) ? $entry['loc'] : ( ! empty( $entry['guid'] ) ? $entry['guid'] : '' ); $location = is_home() ? apply_filters( 'wpml_home_url', get_option( 'home' ) ) : apply_filters( 'wpml_permalink', $entry['loc'], $translation->language_code, true ); if ( $rss ) { $entry['guid'] = $location; continue; } $currentLanguage = ! empty( $activeLanguages[ $translation->language_code ] ) ? $activeLanguages[ $translation->language_code ] : null; $languageCode = ! empty( $currentLanguage['tag'] ) ? $currentLanguage['tag'] : $translation->language_code; if ( $location === $permalink ) { $entry['language'] = $languageCode; continue; } $entry['languages'][] = [ 'language' => $languageCode, 'location' => $location ]; } if ( empty( $entry['languages'] ) ) { unset( $entry['languages'] ); } return $entry; } /** * Returns all post archive entries. * * @since 4.0.0 * * @return array $entries The sitemap entries. */ private function postArchive() { $entries = []; foreach ( aioseo()->sitemap->helpers->includedPostTypes( true ) as $postType ) { if ( aioseo()->dynamicOptions->noConflict()->searchAppearance->archives->has( $postType ) && ! aioseo()->dynamicOptions->searchAppearance->archives->$postType->advanced->robotsMeta->default && aioseo()->dynamicOptions->searchAppearance->archives->$postType->advanced->robotsMeta->noindex ) { continue; } $post = aioseo()->db ->start( aioseo()->db->db->posts . ' as p', true ) ->select( 'p.ID' ) ->where( 'p.post_status', 'publish' ) ->where( 'p.post_type', $postType ) ->limit( 1 ) ->run() ->result(); if ( ! $post ) { continue; } $url = get_post_type_archive_link( $postType ); if ( $url ) { $entries[] = [ 'loc' => $url, 'lastmod' => aioseo()->sitemap->helpers->lastModifiedPostTime( $postType ), 'changefreq' => aioseo()->sitemap->priority->frequency( 'archive' ), 'priority' => aioseo()->sitemap->priority->priority( 'archive' ), ]; } } return apply_filters( 'aioseo_sitemap_post_archives', $entries ); } /** * Returns all term entries for a given taxonomy. * * @since 4.0.0 * * @param string $taxonomy The name of the taxonomy. * @param array $additionalArgs Any additional arguments for the term query. * @return array The sitemap entries. */ public function terms( $taxonomy, $additionalArgs = [] ) { $terms = aioseo()->sitemap->query->terms( $taxonomy, $additionalArgs ); if ( ! $terms ) { return []; } // Get all registered post types for the taxonomy. $postTypes = []; foreach ( get_post_types() as $postType ) { $taxonomies = get_object_taxonomies( $postType ); foreach ( $taxonomies as $name ) { if ( $taxonomy === $name ) { $postTypes[] = $postType; } } } // Return if we're determining the root indexes. if ( ! empty( $additionalArgs['root'] ) && $additionalArgs['root'] ) { return $terms; } $entries = []; foreach ( $terms as $term ) { $entries[] = [ 'loc' => get_term_link( $term->term_id ), 'lastmod' => $this->getTermLastModified( $term->term_id ), 'changefreq' => aioseo()->sitemap->priority->frequency( 'taxonomies', $term, $taxonomy ), 'priority' => aioseo()->sitemap->priority->priority( 'taxonomies', $term, $taxonomy ), 'images' => aioseo()->sitemap->image->term( $term ) ]; } return apply_filters( 'aioseo_sitemap_terms', $entries, $taxonomy ); } /** * Returns the last modified date for a given term. * * @since 4.0.0 * * @param int $termId The term ID. * @return string The lastmod timestamp. */ public function getTermLastModified( $termId ) { $termRelationshipsTable = aioseo()->db->db->prefix . 'term_relationships'; $lastModified = aioseo()->db ->start( aioseo()->db->db->posts . ' as p', true ) ->select( 'MAX(`p`.`post_modified_gmt`) as last_modified' ) ->whereRaw( " ( `p`.`ID` IN ( SELECT `tr`.`object_id` FROM `$termRelationshipsTable` as tr WHERE `tr`.`term_taxonomy_id` = '$termId' ) )" ) ->run() ->result(); if ( empty( $lastModified[0]->last_modified ) ) { return ''; } return aioseo()->helpers->dateTimeToIso8601( $lastModified[0]->last_modified ); } /** * Returns all additional pages. * * @since 4.0.0 * * @return array The sitemap entries. */ public function addl() { $entries = []; if ( 'posts' === get_option( 'show_on_front' ) || ! in_array( 'page', aioseo()->sitemap->helpers->includedPostTypes(), true ) ) { $frontPageId = (int) get_option( 'page_on_front' ); $frontPageUrl = aioseo()->helpers->localizedUrl( '/' ); $post = aioseo()->helpers->getPost( $frontPageId ); $entries[] = [ 'loc' => aioseo()->helpers->maybeRemoveTrailingSlash( $frontPageUrl ), 'lastmod' => $post ? aioseo()->helpers->dateTimeToIso8601( $post->post_modified_gmt ) : aioseo()->sitemap->helpers->lastModifiedPostTime(), 'changefreq' => aioseo()->sitemap->priority->frequency( 'homePage' ), 'priority' => aioseo()->sitemap->priority->priority( 'homePage' ), ]; } if ( aioseo()->options->sitemap->general->additionalPages->enable ) { $additionalPages = aioseo()->options->sitemap->general->additionalPages->pages; $pages = []; foreach ( $additionalPages as $page ) { $additionalPage = json_decode( $page ); if ( empty( $additionalPage->url ) ) { continue; } $pages[] = $additionalPage; } if ( ! count( $pages ) ) { return apply_filters( 'aioseo_sitemap_additional_pages', $entries ); } foreach ( $pages as $page ) { $entries[] = [ 'loc' => $page->url, 'lastmod' => aioseo()->sitemap->helpers->lastModifiedAdditionalPage( $page ), 'isTimezone' => true, 'changefreq' => $page->frequency->value, 'priority' => $page->priority->value ]; } } return apply_filters( 'aioseo_sitemap_additional_pages', $entries ); } /** * Returns all author archive entries. * * @since 4.0.0 * * @return array The sitemap entries. */ public function author() { if ( ! aioseo()->sitemap->helpers->lastModifiedPost() || ! aioseo()->options->sitemap->general->author || ! aioseo()->options->searchAppearance->archives->author->show || ( ! aioseo()->options->searchAppearance->archives->author->advanced->robotsMeta->default && aioseo()->options->searchAppearance->archives->author->advanced->robotsMeta->noindex ) || ( aioseo()->options->searchAppearance->archives->author->advanced->robotsMeta->default && ( ! aioseo()->options->searchAppearance->advanced->globalRobotsMeta->default && aioseo()->options->searchAppearance->advanced->globalRobotsMeta->noindex ) ) ) { return []; } $args = [ 'has_published_posts' => [ 'post' ] ]; $authors = get_users( $args ); if ( ! $authors ) { return []; } $entries = []; foreach ( $authors as $author ) { $entries[] = [ 'loc' => get_author_posts_url( $author->ID ), 'lastmod' => aioseo()->sitemap->helpers->lastModifiedPostTime( 'post', [ 'author' => $author->ID ] ), 'changefreq' => aioseo()->sitemap->priority->frequency( 'author' ), 'priority' => aioseo()->sitemap->priority->priority( 'author' ), ]; } return apply_filters( 'aioseo_sitemap_author_archives', $entries ); } /** * Returns all data archive entries. * * @since 4.0.0 * * @return array The sitemap entries. */ public function date() { if ( ! aioseo()->sitemap->helpers->lastModifiedPost() || ! aioseo()->options->sitemap->general->date || ! aioseo()->options->searchAppearance->archives->date->show || ( ! aioseo()->options->searchAppearance->archives->date->advanced->robotsMeta->default && aioseo()->options->searchAppearance->archives->date->advanced->robotsMeta->noindex ) || ( aioseo()->options->searchAppearance->archives->date->advanced->robotsMeta->default && ( ! aioseo()->options->searchAppearance->advanced->globalRobotsMeta->default && aioseo()->options->searchAppearance->advanced->globalRobotsMeta->noindex ) ) ) { return []; } global $wpdb; $dates = $wpdb->get_results( $wpdb->prepare( "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, post_modified_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_status = 'publish' GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date ASC LIMIT %d", 'post', 50000 ) ); if ( ! $dates ) { return []; } $entries = []; $year = ''; foreach ( $dates as $date ) { $entry = [ 'lastmod' => aioseo()->helpers->dateTimeToIso8601( $date->post_modified_gmt ), 'changefreq' => aioseo()->sitemap->priority->frequency( 'date' ), 'priority' => aioseo()->sitemap->priority->priority( 'date' ), ]; // Include each year only once. if ( $year !== $date->year ) { $year = $date->year; $entry['loc'] = get_year_link( $date->year ); $entries[] = $entry; } $entry['loc'] = get_month_link( $date->year, $date->month ); $entries[] = $entry; } return apply_filters( 'aioseo_sitemap_date_archives', $entries ); } /** * Returns all entries for the RSS Sitemap. * * @since 4.0.0 * * @return array The sitemap entries. */ public function rss() { $posts = aioseo()->sitemap->query->posts( aioseo()->sitemap->helpers->includedPostTypes(), [ 'orderBy' => '`p`.`post_modified_gmt` DESC' ] ); if ( ! count( $posts ) ) { return []; } $entries = []; foreach ( $posts as $post ) { $entry = [ 'guid' => get_permalink( $post->ID ), 'title' => get_the_title( $post ), 'description' => get_post_field( 'post_excerpt', $post->ID ), 'pubDate' => aioseo()->helpers->dateTimeToIso8601( $post->post_modified_gmt ) ]; $entries[] = $this->localizeEntries( $entry, $post, $post->post_type, true ); } usort( $entries, function( $a, $b ) { return $a['pubDate'] < $b['pubDate'] ? 1 : 0; }); return apply_filters( 'aioseo_sitemap_rss', $entries ); } }