관리-도구
편집 파일: class-googlesitemapgeneratorstandardbuilder.php
<?php /** * Default sitemap builder * * @package Sitemap * @author Arne Brachhold * @since 4.0 */ /** * Class */ class GoogleSitemapGeneratorStandardBuilder { private $linkPerPage = 1000; private $maxLinksPerPage = 50000; /** * Creates a new GoogleSitemapGeneratorStandardBuilder instance */ public function __construct() { add_action( 'sm_build_index', array( $this, 'index' ), 10, 1 ); add_action( 'sm_build_content', array( $this, 'content' ), 10, 3 ); add_filter( 'sm_sitemap_for_post', array( $this, 'get_sitemap_url_for_post' ), 10, 3 ); } /** * Generates the content of the requested sitemap * * @param GoogleSitemapGenerator $gsg instance of sitemap generator. * @param String $type the type of the sitemap. * @param String $params Parameters for the sitemap. */ public function content( $gsg, $type, $params ) { $params = strval($params); if (strpos($params, '/') !== false){ $newType = explode('/', $params); $params = end($newType); } switch ( $type ) { case 'pt': $this->build_posts( $gsg, $params ); break; case 'archives': $this->build_archives( $gsg ); break; case 'authors': $this->build_authors( $gsg ); break; case 'tax': $this->build_taxonomies( $gsg, $params ); break; case 'producttags': $this->build_product_tags( $gsg, $params ); break; case 'productcat': $this->build_product_categories( $gsg, $params ); break; case 'externals': $this->build_externals( $gsg ); break; case 'misc': default: $this->build_misc( $gsg ); break; } } /** * Generates the content for the post sitemap * * @param GoogleSitemapGenerator $gsg instance of sitemap generator. * @param string $params string. */ public function build_posts( $gsg, $params ) { $pts = strrpos( $params, '-' ); if ( ! $pts ) { return; } $pts = strrpos( $params, '-', $pts - strlen( $params ) - 1 ); $param_length = count( explode( '-', $params ) ); $post_type = ''; $post_type = substr( $params, 0, $pts ); $type = explode( '-', $post_type ); if ( $param_length > 4 ) { $new = array_slice( $type,0,count($type) -1 ); $post_type = implode( "-", $new ); } else { $post_type = $type[0]; } $limit = $type[count($type)-1]; $limits = substr( $limit, 1 ); $links_per_page = $gsg->get_entries_per_page(); if ( gettype( $links_per_page ) !== 'integer' ) { $links_per_page = (int) 1000; } $limit = ( (int) $limits ) * $links_per_page; if ( ! $post_type || ! in_array( $post_type, $gsg->get_active_post_types(), true ) ) { return; } $params = substr( $params, $pts + 1 ); /** * Global variable for database. * * @var $wpdb wpdb */ global $wpdb; if ( preg_match( '/^([0-9]{4})\-([0-9]{2})$/', $params, $matches ) ) { $year = $matches[1]; $month = $matches[2]; // Excluded posts by ID. $excluded_post_ids = $gsg->get_excluded_post_ids( $gsg ); $not_allowed_slugs = $gsg->robots_disallowed(); $excluded_post_ids = array_unique( array_merge( $excluded_post_ids, $not_allowed_slugs ), SORT_REGULAR ); $gsg->set_option( 'b_exclude', $excluded_post_ids ); $gsg->save_options(); $ex_post_s_q_l = ''; if ( count( $excluded_post_ids ) > 0 ) { $ex_post_s_q_l = 'AND p.ID NOT IN (' . implode( ',', $excluded_post_ids ) . ')'; } // Excluded categories by taxonomy ID. $excluded_category_i_d_s = $gsg->get_excluded_category_i_ds( $gsg ); $ex_cat_s_q_l = ''; if ( count( $excluded_category_i_d_s ) > 0 ) { $ex_cat_s_q_l = "AND ( p.ID NOT IN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} WHERE term_id IN ( " . implode( ',', $excluded_category_i_d_s ) . '))))'; } // Statement to query the actual posts for this post type. $qs = " SELECT p.ID, p.post_author, p.post_status, p.post_name, p.post_parent, p.post_type, p.post_date, p.post_date_gmt, p.post_modified, p.post_modified_gmt, p.comment_count FROM {$wpdb->posts} p WHERE p.post_password = '' AND p.post_type = '%s' AND p.post_status = 'publish' {$ex_post_s_q_l} {$ex_cat_s_q_l} ORDER BY p.post_date_gmt ASC LIMIT %d, %d "; // Query for counting all relevant posts for this post type. $qsc = " SELECT COUNT(*) FROM {$wpdb->posts} p WHERE p.post_password = '' AND p.post_type = '%s' AND p.post_status = 'publish' {$ex_post_s_q_l} {$ex_cat_s_q_l} "; // Calculate the offset based on the limit and links_per_page $offset = max( 0, ( $limit - $links_per_page ) ); // phpcs:disable $q = $wpdb->prepare( $qs, $post_type, $offset, $links_per_page ); // phpcs:enable $posts = $wpdb->get_results( $q ); // phpcs:ignore $post_count = count( $posts ); if ( ( $post_count ) > 0 ) { /** * Description for priority provider * * @var $priority_provider GoogleSitemapGeneratorPrioProviderBase */ $priority_provider = null; if ( $gsg->get_option( 'b_prio_provider' ) !== '' ) { // Number of comments for all posts. $cache_key = __CLASS__ . '::commentCount'; $comment_count = wp_cache_get( $cache_key, 'sitemap' ); if ( false === $comment_count ) { $comment_count = $wpdb->get_var( "SELECT COUNT(*) as `comment_count` FROM {$wpdb->comments} WHERE `comment_approved`='1'" ); // db call ok. wp_cache_set( $cache_key, $comment_count, 'sitemap', 20 ); } // Number of all posts matching our criteria. $cache_key = __CLASS__ . "::totalPostCount::$post_type"; $total_post_count = wp_cache_get( $cache_key, 'sitemap' ); if ( false === $total_post_count ) { // phpcs:disable $total_post_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->posts} p WHERE p.post_password = '' AND p.post_type = '%s' AND p.post_status = 'publish' " . $ex_post_s_q_l . " " . $ex_cat_s_q_l . " ", $post_type ) // phpcs:ignore ); // db call ok. // phpcs:enable wp_cache_add( $cache_key, $total_post_count, 'sitemap', 20 ); } // Initialize a new priority provider. $provider_class = $gsg->get_option( 'b_prio_provider' ); $priority_provider = new $provider_class( $comment_count, $total_post_count ); } // Default priorities. $default_priority_for_posts = $gsg->get_option( 'pr_posts' ); $default_priority_for_pages = $gsg->get_option( 'pr_pages' ); // Minimum priority. $minimum_priority = $gsg->get_option( 'pr_posts_min' ); // Change frequencies. $change_frequency_for_posts = $gsg->get_option( 'cf_posts' ); $change_frequency_for_pages = $gsg->get_option( 'cf_pages' ); // Page as home handling. $home_pid = 0; $home = get_home_url(); if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) { $page_on_front = get_option( 'page_on_front' ); $p = get_post( $page_on_front ); if ( $p ) { $home_pid = $p->ID; } } $siteLanguages = []; $defaultLanguageCode = ''; if (function_exists('icl_get_languages')) { if (function_exists('icl_get_default_language')) $defaultLanguageCode = icl_get_default_language(); $languages = icl_get_languages('skip_missing=0'); if($languages){ foreach ($languages as $language) { if($defaultLanguageCode !== $language['language_code']) $siteLanguages[] = $language['language_code']; } } } else if (function_exists('pll_the_languages')) { if (function_exists('pll_default_language')) $defaultLanguageCode = pll_default_language(); $languages = pll_the_languages(array('raw' => 1)); if ($languages) { foreach ($languages as $language) { if($defaultLanguageCode !== $language['slug']) $siteLanguages[] = $language['slug']; } } } foreach ( $posts as $post ) { $permalink = get_permalink( $post ); $permalink = apply_filters( 'sm_xml_sitemap_post_url', $permalink, $post ); if(count($siteLanguages) > 0){ $structurekArr = explode('/', get_option('permalink_structure')); $postLinkArr = explode('/', $permalink); $index = null; if(is_array($structurekArr) && is_array($postLinkArr)){ foreach ($siteLanguages as $lang){ if (in_array($lang, $postLinkArr)) { $index = array_search($lang, $postLinkArr); } } } if ($index !== null) { if ($postLinkArr[$index] !== $defaultLanguageCode) { $custom_post_type_name = get_post_type($post); if (!in_array($custom_post_type_name, $postLinkArr)) { $key = array_search('%postname%', $structurekArr); if ($structurekArr[$key] === '%postname%') { $postLinkArr[$index + $key] = $post->post_name; } } $permalink = implode('/', $postLinkArr); } } } // Exclude the home page and placeholder items by some plugins. Also include only internal links. if ( ( ! empty( $permalink ) ) && $permalink !== $home && $post->ID !== $home_pid && strpos( $permalink, $home ) !== false ) { // Default Priority if auto calc is disabled. $priority = ( 'page' === $post_type ? $default_priority_for_pages : $default_priority_for_posts ); // If priority calc. is enabled, calculate (but only for posts, not pages)! if ( null !== $priority_provider && 'post' === $post_type ) { $priority = $priority_provider->get_post_priority( $post->ID, $post->comment_count, $post ); } // Ensure the minimum priority. if ( 'post' === $post_type && $minimum_priority > 0 && $priority < $minimum_priority ) { $priority = $minimum_priority; } // Add the URL to the sitemap. $gsg->add_url( $permalink, $gsg->get_timestamp_from_my_sql( $post->post_modified_gmt && '0000-00-00 00:00:00' !== $post->post_modified_gmt ? $post->post_modified_gmt : $post->post_date_gmt ), ( 'page' === $post_type ? $change_frequency_for_pages : $change_frequency_for_posts ), $priority, $post->ID ); } // Why not use clean_post_cache? Because some plugin will go crazy then (lots of database queries). // The post cache was not populated in a clean way, so we also won't delete it using the API. // wp_cache_delete( $post->ID, 'posts' );. unset( $post ); } unset( $posts_custom ); } } } /** * Generates the content for the archives sitemap * * @param GoogleSitemapGenerator $gsg object of google sitemap. */ public function build_archives( $gsg ) { /** * Super global variable for database. * * @var $wpdb wpdb */ global $wpdb; $now = current_time( 'mysql', true ); $archives = $wpdb->get_results( // phpcs:disable $wpdb->prepare( "SELECT DISTINCT YEAR(post_date_gmt) AS `year`, MONTH(post_date_gmt) AS `month`, MAX(post_date_gmt) AS last_mod, count(ID) AS posts FROM $wpdb->posts WHERE post_date_gmt < '%s' AND post_status = 'publish' AND post_type = 'post' GROUP BY YEAR(post_date_gmt), MONTH(post_date_gmt) ORDER BY post_date_gmt DESC", $now ) // phpcs:enable ); // db call ok; no-cache ok. if ( $archives ) { foreach ( $archives as $archive ) { $url = get_month_link( $archive->year, $archive->month ); // Archive is the current one. if ( gmdate( 'n' ) === $archive->month && gmdate( 'Y' ) === $archive->year ) { $change_freq = $gsg->get_option( 'cf_arch_curr' ); } else { // Archive is older. $change_freq = $gsg->get_option( 'cf_arch_old' ); } $gsg->add_url( $url, $gsg->get_timestamp_from_my_sql( $archive->last_mod ), $change_freq, $gsg->get_option( 'pr_arch' ) ); } } $post_type_customs = get_post_types( array( 'public' => 1 ) ); $post_type_customs = array_diff( $post_type_customs, array( 'page', 'attachment', 'product', 'post' ) ); foreach ( $post_type_customs as $post_type_custom ) { $latest = new WP_Query( array( 'post_type' => $post_type_custom, 'post_status' => 'publish', 'posts_per_page' => 1, 'orderby' => 'modified', 'order' => 'DESC', ) ); if ( $latest->have_posts() ) { $modified_date = $latest->posts[0]->post_modified; if ( gmdate( 'n', strtotime( $modified_date ) ) === gmdate( 'n' ) && gmdate( 'Y', strtotime( $modified_date ) ) === gmdate( 'Y' ) ) { $change_freq = $gsg->get_option( 'cf_arch_curr' ); } else { // Archive is older. $change_freq = $gsg->get_option( 'cf_arch_old' ); } $gsg->add_url( get_post_type_archive_link( $post_type_custom ), $gsg->get_timestamp_from_my_sql( $modified_date ), $change_freq, $gsg->get_option( 'pr_arch' ), 0, array(), array(), '' ); } } } /** * Generates the misc sitemap * * @param GoogleSitemapGenerator $gsg instence of sitemap generator class. */ public function build_misc( $gsg ) { $lm = get_lastpostmodified( 'gmt' ); if ( $gsg->get_option( 'in_home' ) ) { $home = get_bloginfo( 'url' ); // Add the home page (WITH a slash!). if ( $gsg->get_option( 'in_home' ) ) { if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) { $page_on_front = get_option( 'page_on_front' ); $p = get_post( $page_on_front ); if ( $p ) { $gsg->add_url( trailingslashit( $home ), $gsg->get_timestamp_from_my_sql( ( $p->post_modified_gmt && '0000-00-00 00:00:00' !== $p->post_modified_gmt ? $p->post_modified_gmt : $p->post_date_gmt ) ), $gsg->get_option( 'cf_home' ), $gsg->get_option( 'pr_home' ) ); } } else { $gsg->add_url( trailingslashit( $home ), ( $lm ? $gsg->get_timestamp_from_my_sql( $lm ) : time() ), $gsg->get_option( 'cf_home' ), $gsg->get_option( 'pr_home' ) ); } } } if ( $gsg->is_xsl_enabled() && true === $gsg->get_option( 'b_html' ) ) { if(is_multisite()) { if(isset(get_blog_option( get_current_blog_id(), 'sm_options' )['sm_b_sitemap_name'])) { $sm_sitemap_name = get_blog_option( get_current_blog_id(), 'sm_options' )['sm_b_sitemap_name']; } } else if(isset(get_option('sm_options')['sm_b_sitemap_name'])) $sm_sitemap_name = get_option('sm_options')['sm_b_sitemap_name']; if(!isset($sm_sitemap_name)) $sm_sitemap_name = 'sitemap'; $gsg->add_url( str_replace('.html', $sm_sitemap_name . '.html', $gsg->get_xml_url( 'main', '', array( 'html' => true ) ) ), ( $lm ? $gsg->get_timestamp_from_my_sql( $lm ) : time() ) ); } do_action( 'sm_buildmap' ); } /** * Generates the author sitemap * * @param GoogleSitemapGenerator $gsg instence of sitemap generator class. */ public function build_authors( $gsg ) { /** * Use the wpdb global variable * * @var $wpdb wpdb * */ global $wpdb; // Unfortunately there is no API function to get all authors, so we have to do it the dirty way... // We retrieve only users with published and not password protected enabled post types. $enabled_post_types = null; $enabled_post_types = $gsg->get_active_post_types(); // Ensure we count at least the posts... $enabled_post_types_count = count( $enabled_post_types ); if ( 0 === $enabled_post_types_count ) { $enabled_post_types[] = 'post'; } $sql = "SELECT DISTINCT u.ID, u.user_nicename, MAX(p.post_modified_gmt) AS last_post FROM {$wpdb->users} u, {$wpdb->posts} p WHERE p.post_author = u.ID AND p.post_status = 'publish' AND p.post_type IN(" . implode( ', ', array_fill( 0, count( $enabled_post_types ), '%s' ) ) . ") AND p.post_password = '' GROUP BY u.ID, u.user_nicename"; $query = call_user_func_array( array( $wpdb, 'prepare' ), array_merge( array( $sql ), $enabled_post_types ) ); $authors = $wpdb->get_results( $query ); // phpcs:ignore if ( $authors && is_array( $authors ) ) { $authors = $this->exclude_authors( $authors ); if ( ! empty( $authors ) ) { foreach ( $authors as $author ) { $url = get_author_posts_url( $author->ID, $author->user_nicename ); $gsg->add_url( $url, $gsg->get_timestamp_from_my_sql( $author->last_post ), $gsg->get_option( 'cf_auth' ), $gsg->get_option( 'pr_auth' ) ); } } } } /** * Wrap legacy filter to deduplicate calls. * * @param array $users Array of user objects to filter. * * @return array */ protected function exclude_authors( $authors ) { /** * Filter the authors, included in XML sitemap. * * @param array $authors Array of user objects to filter. */ return apply_filters( 'sm_sitemap_exclude_author', $authors ); } /** * Filters the terms query to only include published posts * * @param string[] $selects Array of string. * @return string[] */ public function filter_terms_query( $selects ) { /** * Global variable in functional scope for database * * @var wpdb $wpdb Global variable for wpdb */ global $wpdb; $selects[] = " ( /* ADDED BY XML SITEMAPS */ SELECT UNIX_TIMESTAMP(MAX(p.post_date_gmt)) as _mod_date FROM {$wpdb->posts} p, {$wpdb->term_relationships} r WHERE p.ID = r.object_id AND p.post_status = 'publish' AND p.post_password = '' AND r.term_taxonomy_id = tt.term_taxonomy_id ) as _mod_date /* END ADDED BY XML SITEMAPS */ "; return $selects; } /** * Generates the taxonomies sitemap * * @param GoogleSitemapGenerator $gsg Instance of sitemap generator. * @param string $taxonomy The Taxonomy. */ public function build_taxonomies( $gsg, $taxonomy ) { $offset = $taxonomy; $links_per_page = $gsg->get_entries_per_page(); if ( gettype( $links_per_page ) !== 'integer' ) { $links_per_page = (int)1000; } if ( strpos( $taxonomy, '-' ) !== false ) { $offset = substr( $taxonomy, strrpos( $taxonomy, '-' ) + 1 ); $taxonomy = str_replace( '-' . $offset, '', $taxonomy ); } else { $offset = 1; } $temp_offset = $offset; $offset = intval( $offset ); if ( 0 === $offset ) { $taxonomy = $taxonomy . '-' . $temp_offset; $links_per_page = $this->linkPerPage; } else { $offset = ( --$offset ) * $links_per_page; } $enabled_taxonomies = $this->get_enabled_taxonomies( $gsg ); if ( in_array( $taxonomy, $enabled_taxonomies, true ) ) { $excludes = array(); $excl_cats = $gsg->get_option( 'b_exclude_cats' ); // Excluded cats. if ( $excl_cats ) { $excludes = $excl_cats; } add_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); /* $terms = get_terms( $taxonomy, array( 'number' => $links_per_page, 'offset' => $offset, 'hide_empty' => true, 'hierarchical' => false, 'exclude' => $excludes, ) ); */ $queryArr = [ 'taxonomy' => $taxonomy, 'number' => $links_per_page, 'offset' => $offset, 'exclude' => $excludes, ]; $queryArr['hide_empty'] = apply_filters( 'sm_sitemap_taxonomy_hide_empty', true ); if (preg_match('/(post_tag|category)/', $taxonomy)) { $queryArr['hierarchical'] = false; } $terms = array_values( array_unique( array_filter( $this->get_terms($queryArr), function ($term) use ($taxonomy) { return $term->taxonomy === $taxonomy; } ), SORT_REGULAR ) ); remove_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); //$terms = array_values(array_unique($terms, SORT_REGULAR)); /** * Filter: 'sm_exclude_from_sitemap_by_term_ids' - Allow excluding terms by ID. * * @param array $terms_to_exclude The terms to exclude. */ $terms_to_exclude = apply_filters( 'sm_exclude_from_sitemap_by_term_ids', [] ); $step = 1; $size_of_terms = count( $terms ); for ( $tax_count = 0; $tax_count < $size_of_terms; $tax_count++ ) { $term = $terms[ $tax_count ]; if ( in_array( $term->term_id, $terms_to_exclude ) ) { $step++; continue; } switch ( $term->taxonomy ) { case 'category': $gsg->add_url( get_term_link( $term, $step ), $this->getTaxonomyUpdatedDate($term->term_id) ?: 0, $gsg->get_option( 'cf_cats' ), $gsg->get_option( 'pr_cats' ) ); break; case 'product_cat': $gsg->add_url( get_term_link( $term, $step ), $term->_mod_date, $gsg->get_option( 'cf_product_cat' ), $gsg->get_option( 'pr_product_cat' ) ); break; case 'post_tag': $gsg->add_url( get_term_link( $term, $step ), $this->getTaxonomyUpdatedDate($term->term_id) ?: 0, $gsg->get_option( 'cf_tags' ), $gsg->get_option( 'pr_tags' ) ); break; default: $gsg->add_url( get_term_link( $term, $step ), $this->getTaxonomyUpdatedDate($term->term_id) ?: 0, $gsg->get_option( 'cf_' . $term->taxonomy ), $gsg->get_option( 'pr_' . $term->taxonomy ) ); break; } $step++; } } } /* get last updated date of taxonomy post returns timestamp (int) */ private function getTaxonomyUpdatedDate($term_id){ global $wpdb; $query = $wpdb->prepare(" SELECT p.* FROM {$wpdb->posts} p INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.term_id = %d ORDER BY p.post_date DESC LIMIT 1 ", $term_id); $post = $wpdb->get_row($query); if ($post) { return strtotime($post->post_date); } } /** * Returns the enabled taxonomies. Only taxonomies with posts are returned. * * @param GoogleSitemapGenerator $gsg Google sitemap generator's instance. * @return array */ public function get_enabled_taxonomies( GoogleSitemapGenerator $gsg ) { $enabled_taxonomies = $gsg->get_option( 'in_tax' ); if ( $gsg->get_option( 'in_tags' ) ) { $enabled_taxonomies[] = 'post_tag'; } if ( $gsg->get_option( 'in_cats' ) ) { $enabled_taxonomies[] = 'category'; } return $enabled_taxonomies; } /** * Returns the enabled Product tags. Only Product Tags with posts are returned. * * @param GoogleSitemapGenerator $gsg Instance of sitemap generator. * @param int $offset Offset. * @return void */ public function build_product_tags( GoogleSitemapGenerator $gsg, $offset ) { $links_per_page = $gsg->get_entries_per_page(); if ( gettype( $links_per_page ) !== 'integer' ) { $links_per_page = (int) 1000; } $offset = (intval(--$offset)) * $links_per_page; add_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); $terms = get_terms( 'product_tag', array( 'number' => $links_per_page, 'offset' => $offset, ) ); remove_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); $term_array = array(); if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) { foreach ( $terms as $term ) { $term_array[] = $term->name; $url = get_term_link( $term ); //$gsg->add_url( $url, $term->_mod_date, $gsg->get_option( 'cf_tags' ), $gsg->get_option( 'pr_tags' ), $term->ID, array(), array(), '' ); $gsg->add_url( $url, $this->getProductUpdatedDate($term->term_id, 'product_tag'), $gsg->get_option( 'cf_tags' ), $gsg->get_option( 'pr_tags' ), $term->ID, array(), array(), '' ); } } } /** * Returns the enabled Product Categories. Only Product Categories with posts are returned. * * @param GoogleSitemapGenerator $gsg Instance of sitemap generator. * @param int $offset Offset. * @return void */ public function build_product_categories( GoogleSitemapGenerator $gsg, $offset ) { $links_per_page = $gsg->get_entries_per_page(); if ( gettype( $links_per_page ) !== 'integer' ) { //$links_per_page = (int) 1000; $links_per_page = (int)$links_per_page; } $offset = (intval(--$offset)) * $links_per_page; $excludes = array(); $excl_cats = $gsg->get_option( 'b_exclude_cats' ); // Excluded cats. if ( $excl_cats ) { $excludes = $excl_cats; } add_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); $category = get_terms( 'product_cat', array( 'number' => $links_per_page, 'offset' => $offset, 'exclude' => $excludes, ) ); remove_filter( 'get_terms_fields', array( $this, 'filter_terms_query' ), 20, 2 ); $cat_array = array(); if ( ! empty( $category ) && ! is_wp_error( $category ) ) { $step = 1; foreach ( $category as $cat ) { $cat_array[] = $cat->name; if ( $cat && wp_count_terms( $cat->name, array( 'hide_empty' => true ) ) > 0 ) { $step++; $url = get_term_link( $cat ); $gsg->add_url( $url, $this->getProductUpdatedDate($cat->term_id, 'product_cat'), $gsg->get_option( 'cf_product_cat' ), $gsg->get_option( 'pr_product_cat' ), $cat->ID, array(), array(), '' ); } } } } /* Get last product updated date by tag ID */ private function getProductUpdatedDate($term_id, $taxonomy){ $args = array( 'post_type' => 'product', 'posts_per_page' => 1, 'tax_query' => array( array( 'taxonomy' => $taxonomy, 'field' => 'id', 'terms' => $term_id, ), ), 'orderby' => 'modified', 'order' => 'DESC', ); $products = new WC_Product_Query($args); $product_results = $products->get_products(); if ($product_results) { $product = array_shift($product_results); $updated_date = strtotime($product->get_date_modified()->date('Y-m-d H:i:s')); return $updated_date; } return false; } /** * Generates the external sitemap * * @param GoogleSitemapGenerator $gsg Instance of sitemap generator. */ public function build_externals( $gsg ) { $pages = $gsg->get_pages(); if ( $pages && is_array( $pages ) && count( $pages ) > 0 ) { foreach ( $pages as $page ) { // Disabled phpcs for backward compatibility . // phpcs:disable $url = ! empty( $page->get_url() ) ? $page->get_url() : $page->url; $change_freq = ! empty( $page->get_change_freq() ) ? $page->get_change_freq() : $page->change_freq; $priority = ! empty( $page->get_priority() ) ? $page->get_priority() : $page->priority; $last_mod = ! empty( $page->get_last_mod() ) ? $page->get_last_mod() : $page->last_mod; // phpcs:enable /** * Description for $page variable. * * @var $page GoogleSitemapGeneratorPage */ $gsg->add_url( $url, $last_mod, $change_freq, $priority ); } } } /** * Generates the sitemap index * * @param GoogleSitemapGenerator $gsg Instance of sitemap generator. */ public function index( $gsg ) { /** * Global variable for database. * * @var $wpdb wpdb */ global $wpdb; $blog_update = strtotime( get_lastpostmodified( 'gmt' ) ); $links_per_page = $gsg->get_entries_per_page(); if ( 0 === $links_per_page || is_nan( $links_per_page ) ) { $links_per_page = $this->linkPerPage; $gsg->set_option( 'links_page', $this->linkPerPage ); } else if ($links_per_page > $this->maxLinksPerPage) $links_per_page = $this->maxLinksPerPage; $gsg->add_sitemap( 'misc', null, $blog_update ); /** * Filter: 'sm_sitemap_exclude_taxonomy' - Allow extending and modifying the taxonomies to exclude. * * @param array $taxonomies_to_exclude The taxonomies to exclude. */ $taxonomies_to_exclude = []; $default_taxonomies_to_exclude = [ 'product_tag', 'product_cat' ]; $taxonomies_to_exclude = apply_filters( 'sm_sitemap_exclude_taxonomy', $taxonomies_to_exclude ); if ( ! is_array( $taxonomies_to_exclude ) || empty( $taxonomies_to_exclude ) ) { $taxonomies_to_exclude = $default_taxonomies_to_exclude; } else { $taxonomies_to_exclude = array_merge( $taxonomies_to_exclude, $default_taxonomies_to_exclude ); } $enabled_taxonomies = $this->get_enabled_taxonomies( $gsg ); $excl_cats = $gsg->get_option( 'b_exclude_cats' ); $excludes = $excl_cats ? $excl_cats : array(); $terms_by_taxonomy = array(); foreach ( $enabled_taxonomies as $taxonomy ) { if ( ! in_array( $taxonomy, $taxonomies_to_exclude, true ) ) { $terms_args = [ 'taxonomy' => $taxonomy, 'exclude' => $excludes ]; $terms_args['hide_empty'] = apply_filters( 'sm_sitemap_taxonomy_hide_empty', true ); $terms = $this->get_terms( $terms_args ); $terms_by_taxonomy[ $taxonomy ] = $terms; } } foreach ( $terms_by_taxonomy as $taxonomy => $terms ) { $step = 1; $i = 0; foreach ( $terms as $term ) { if ( 0 === ( $i % $links_per_page ) && '' !== $term->taxonomy && taxonomy_exists( $term->taxonomy ) ) { $gsg->add_sitemap( $term->taxonomy,'-sitemap' . ($step === 1? '' : $step), $blog_update ); $step++; } $i++; } } // If Product Tags is enabled from sitemap settings. if ( true === $gsg->get_option( 'product_tags' ) ) { $product_tags = get_terms( 'product_tag' ); if ( ! empty( $product_tags ) && ! is_wp_error( $product_tags ) ) { $step = 1; $product_tags_size_of = count( $product_tags ); for ( $product_count = 0; $product_count < $product_tags_size_of; $product_count++ ) { if ( 0 === ( $product_count % $links_per_page ) ) { //$gsg->add_sitemap( 'producttags', $step, $blog_update ); $gsg->add_sitemap( 'producttags', '-sitemap' . ($step === 1? '' : $step), $blog_update ); $step = ++$step; } } } } // If Product category is enabled from sitemap settings. if ( true === $gsg->get_option( 'in_product_cat' ) ) { $excludes = array(); $excl_cats = $gsg->get_option( 'b_exclude_cats' ); // Excluded cats. if ( $excl_cats ) { $excludes = $excl_cats; } $product_cat = get_terms( 'product_cat', array( 'exclude' => $excludes ) ); if ( ! empty( $product_cat ) && ! is_wp_error( $product_cat ) ) { $step = 1; $product_cat_count = count( $product_cat ); for ( $product_count = 0; $product_count < $product_cat_count; $product_count++ ) { if ( 0 === ( $product_count % $links_per_page ) ) { //$gsg->add_sitemap( 'productcat', $step, $blog_update ); $gsg->add_sitemap( 'productcat', '-sitemap' . ($step === 1? '' : $step), $blog_update ); $step = ++$step; } } } } $pages = (array)$gsg->get_pages(); if ( count( $pages ) > 0 ) { foreach ( $pages as $page ) { $url = ! empty( $page->get_url() ) ? $page->get_url() : ( property_exists( $page, '_url' ) ? $page->_url : '' ); if ( $page instanceof GoogleSitemapGeneratorPage && $url ) { $gsg->add_sitemap( 'externals-sitemap', null, $blog_update ); break; } } } $enabled_post_types = $gsg->get_active_post_types(); //checking for products enabled if($gsg->get_option( 'in_product_assortment' ) !== null && $gsg->get_option( 'in_product_assortment' ) !== true){ $enabled_post_types = array_filter($enabled_post_types, function($value) { return $value !== 'product'; }); } $has_enabled_post_types_posts = false; $has_posts = false; if ( count( $enabled_post_types ) > 0 ) { $excluded_post_ids = $gsg->get_excluded_post_ids( $gsg ); $not_allowed_slugs = $gsg->robots_disallowed(); $excluded_post_ids = array_unique( array_merge( $excluded_post_ids, $not_allowed_slugs ), SORT_REGULAR ); $gsg->set_option( 'b_exclude', $excluded_post_ids ); $gsg->save_options(); $ex_post_s_q_l = ''; $excluded_post_ids_count = count( $excluded_post_ids ); if ( $excluded_post_ids_count > 0 ) { $ex_post_s_q_l = 'AND p.ID NOT IN (' . implode( ',', $excluded_post_ids ) . ')'; } $excluded_category_i_d_s = $gsg->get_excluded_category_i_ds( $gsg ); $ex_cat_s_q_l = ''; $excluded_category_i_d_s_count = count( $excluded_category_i_d_s ); if ( $excluded_category_i_d_s_count > 0 ) { $ex_cat_s_q_l = "AND ( p.ID NOT IN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN (" . implode( ',', $excluded_category_i_d_s ) . ')))'; } foreach ( $enabled_post_types as $post_type_custom ) { // phpcs:disable $prp = $wpdb->prepare( "SELECT COUNT(p.ID) AS `numposts`, MAX(p.post_modified_gmt) as `last_mod` FROM {$wpdb->posts} p WHERE p.post_password = '' AND p.post_type = '%s' AND p.post_status = 'publish' " . $ex_post_s_q_l . "" . $ex_cat_s_q_l . " ORDER BY p.post_date_gmt DESC", $post_type_custom ); $posts = $wpdb->get_results($prp); if ( $posts ) { if ( 'post' === $post_type_custom ) { $has_posts = true; } $has_enabled_post_types_posts = true; foreach ( $posts as $post ) { $step = 1; for ( $i = 0; $i < $post->numposts; $i++ ) { if ( 0 === ( $i % $links_per_page ) ) { //$gsg->add_sitemap( 'pt', $post_type_custom . '-p' . $step . '-' . sprintf( '%04d-%02d', $post->year, $post->month ), $gsg->get_timestamp_from_my_sql( $post->last_mod ), 'p' . $step ); $gsg->add_sitemap( 'pt', $post_type_custom . '-sitemap' . ($step === 1? '' : $step) , $gsg->get_timestamp_from_my_sql( $post->last_mod ) ); $step = ++$step; } } // $gsg->add_sitemap( 'pt', $post_type_custom . '-' . sprintf( '%04d-%02d', $post->year, $post->month ), $gsg->get_timestamp_from_my_sql( $post->last_mod ) ); } } // phpcs:enable } } // Only include authors if there is a public post with a enabled post type. if ( $gsg->get_option( 'in_auth' ) && $has_enabled_post_types_posts ) { $gsg->add_sitemap( 'authors-sitemap', null, $blog_update ); } // Only include archived if there are posts with postType post. if ( $gsg->get_option( 'in_arch' ) && $has_posts ) { $gsg->add_sitemap( 'archives-sitemap', null, $blog_update ); } /** * Filter: 'sm_sitemap_index' - Allow extending and modifying the xml links to include. * * @param array $sitemap_custom_items The custom xml link to include. */ $sitemap_custom_items = []; $sitemap_custom_items = apply_filters( 'sm_sitemap_index', $sitemap_custom_items ); if ( ! is_array( $sitemap_custom_items ) ) { $sitemap_custom_items = []; } if ( ! empty( $sitemap_custom_items ) ) { foreach ( $sitemap_custom_items as $sitemap_custom_item ) { $title = ( isset( $sitemap_custom_item['title'] ) ) ? $sitemap_custom_item['title'] : ''; $modified = ( isset( $sitemap_custom_item['modified'] ) ) ? strtotime( $sitemap_custom_item['modified'] ) : ''; if ( $title != '' && $modified != '' ) { $gsg->add_sitemap( $title, null, $modified ); } } } } /** * Return the URL to the sitemap related to a specific post * * @param array $urls Post sitemap urls. * @param GoogleSitemapGenerator $gsg Instance of google sitemap generator. * @param int $post_id The post ID. * * @return string[] */ public function get_sitemap_url_for_post( array $urls, $gsg, $post_id ) { $post = get_post( $post_id ); if ( $post ) { $last_modified = $gsg->get_timestamp_from_my_sql( $post->post_modified_gmt ); $url = $gsg->get_xml_url( 'pt', $post->post_type . '-' . gmdate( 'Y-m', $last_modified ) ); $urls[] = $url; } return $urls; } public function get_terms( $args = [] ) { global $wpdb; $taxonomy = ( isset( $args['taxonomy'] ) && null !== $args['taxonomy'] ) ? $args['taxonomy'] : false; $sql = 'SELECT DISTINCT *'; $sql .= ' FROM '.$wpdb->prefix.'terms as t'; $sql .= ' INNER JOIN '.$wpdb->prefix.'term_taxonomy as tt'; $sql .= ' WHERE `tt`.taxonomy = \'' . $taxonomy . '\''; $sql .= ' AND `tt`.term_id = `t`.term_id'; if ( ! empty( $args ) ) { if ( isset( $args['hide_empty'] ) && $args['hide_empty'] === true ) { $sql .= ' AND `tt`.count != 0'; } if ( isset( $args['hierarchical'] ) && $args['hierarchical'] === true ) { $sql .= ' AND `tt`.parent != 0'; } if ( isset( $args['exclude'] ) && is_array( $args['exclude'] ) && ! empty( $args['exclude'] ) ) { foreach ( $args['exclude'] as $term_id ) { $sql .= ' AND `tt`.term_id != ' . $term_id; } } $sql .= ' ORDER BY t.name ASC'; if ( isset( $args['number'] ) && $args['number'] != '' ) { $sql .= ' LIMIT ' . $args['number']; } if ( isset( $args['offset'] ) && $args['offset'] != '' ) { $sql .= ' OFFSET ' . $args['offset']; } } $result = $wpdb->get_results($sql); return $result; } } if ( defined( 'WPINC' ) ) { new GoogleSitemapGeneratorStandardBuilder(); }