%PDF- %PDF-
Direktori : /var/www/pn/beta/64801_wp-content/plugins/autodescription/inc/classes/ |
Current File : /var/www/pn/beta/64801_wp-content/plugins/autodescription/inc/classes/sitemaps.class.php |
<?php /** * @package The_SEO_Framework\Classes */ namespace The_SEO_Framework; defined( 'ABSPATH' ) or die; /** * The SEO Framework plugin * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (https://cyberwire.nl/) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Class The_SEO_Framework\Sitemaps * * Handles sitemap output. * * @since 2.8.0 */ class Sitemaps extends Metaboxes { /** * Maximum number of posts that show up in the sitemap.xml page. * * @since 2.2.9 * * @var int Max Posts in Sitemap */ protected $max_posts; /** * Checks for pretty permalinks. * * @since 2.2.9 * * @var bool true if pretty */ protected $pretty_permalinks; /** * Checks if sitemap is being output. * * @since 2.5.2 * * @var bool true if sitemap is being output. */ protected $doing_sitemap = false; /** * Constructor, load parent constructor and set up caches. */ protected function __construct() { parent::__construct(); } /** * Determines whether we can output sitemap or not based on options and blog status. * * @since 2.6.0 * @since 2.9.2 : Now returns true when using plain and ugly permalinks. * @staticvar bool $cache * * @return bool */ public function can_run_sitemap() { static $cache = null; if ( isset( $cache ) ) return $cache; /** * Don't do anything on a deleted or spam blog on MultiSite. * There's nothing to find anyway. */ return $cache = $this->is_option_checked( 'sitemaps_output' ) && false === $this->current_blog_is_spam_or_deleted(); } /** * Adds rewrite rule to WordPress * This rule defines the sitemap.xml output * * @since 2.2.9 * * @param bool $force add the rule anyway, regardless of detected environment. */ public function rewrite_rule_sitemap( $force = false ) { //* Adding rewrite rules only has effect when permalink structures are active. if ( $this->can_run_sitemap() || $force ) { /** * Don't do anything if a sitemap plugin is active. * On sitemap plugin activation, the sitemap plugin should flush the * rewrite rules. If it doesn't, then this plugin's sitemap will be called. */ if ( $this->detect_sitemap_plugin() ) return; \add_rewrite_rule( 'sitemap\.xml$', 'index.php?the_seo_framework_sitemap=xml', 'top' ); \add_rewrite_rule( 'sitemap\.xsl$', 'index.php?the_seo_framework_sitemap=xsl', 'top' ); } } /** * Registers the_seo_framework_sitemap to WP_Query. * * @since 2.2.9 * * @param array $vars The WP_Query variables. * @return array $vars The adjusted vars. */ public function enqueue_sitemap_query_vars( $vars ) { if ( $this->can_run_sitemap() ) { $vars[] = 'the_seo_framework_sitemap'; } return $vars; } /** * Outputs sitemap.xml 'file' and header on sitemap query. * Also cleans up globals and sets up variables. * * @since 2.2.9 */ public function maybe_output_sitemap() { if ( $this->can_run_sitemap() ) { global $wp_query; if ( isset( $wp_query->query_vars['the_seo_framework_sitemap'] ) && 'xml' === $wp_query->query_vars['the_seo_framework_sitemap'] ) { // Don't let WordPress think this is 404. $wp_query->is_404 = false; $this->doing_sitemap = true; /** * Applies filters 'the_seo_framework_sitemap_post_limit' : int * @since 2.2.9 * @since 2.8.0 Increased to 1200 from 700. */ $this->max_posts = (int) \apply_filters( 'the_seo_framework_sitemap_post_limit', 1200 ); /** * Set at least 2000 variables free. * Freeing 0.15MB on a clean WordPress installation. * @since 2.6.0 */ $this->clean_up_globals_for_sitemap(); $this->output_sitemap(); } } } /** * Outputs sitemap.xsl 'file' and header on sitemap stylesheet query. * * @since 2.2.9 */ public function maybe_output_sitemap_stylesheet() { if ( $this->can_run_sitemap() ) { global $wp_query; if ( isset( $wp_query->query_vars['the_seo_framework_sitemap'] ) && 'xsl' === $wp_query->query_vars['the_seo_framework_sitemap'] ) { // Don't let WordPress think this is 404. $wp_query->is_404 = false; $this->doing_sitemap = true; $this->output_sitemap_xsl_stylesheet(); } } } /** * Destroys unused $GLOBALS. To be used prior to outputting sitemap. * * @since 2.6.0 * @since 2.8.0 Renamed from clean_up_globals(). * * @param bool $get_freed_memory Whether to return the freed memory in bytes. * @return int $freed_memory */ protected function clean_up_globals_for_sitemap( $get_freed_memory = false ) { static $freed_memory = null; if ( $get_freed_memory ) return $freed_memory; $this->the_seo_framework_debug and $memory = memory_get_usage(); $remove = array( 'wp_filter' => array( 'wp_head', 'admin_head', 'the_content', 'the_content_feed', 'the_excerpt_rss', 'wp_footer', 'admin_footer', ), 'wp_registered_widgets', 'wp_registered_sidebars', 'wp_registered_widget_updates', 'wp_registered_widget_controls', '_wp_deprecated_widgets_callbacks', 'posts', 'shortcode_tags', ); foreach ( $remove as $key => $value ) { if ( is_array( $value ) ) { foreach ( $value as $v ) unset( $GLOBALS[ $key ][ $v ] ); } else { unset( $GLOBALS[ $value ] ); } } $this->the_seo_framework_debug and $freed_memory = $memory - memory_get_usage(); } /** * Outputs sitemap.xml 'file' and header. * * @since 2.2.9 */ protected function output_sitemap() { //* Remove output, if any. $this->clean_response_header(); if ( ! headers_sent() ) header( 'Content-type: text/xml; charset=utf-8' ); //* Fetch sitemap content and add trailing line. Already escaped internally. $this->output_sitemap_content(); echo "\n"; // We're done now. exit; } /** * Output sitemap.xml content from transient. * * @since 2.8.0 * * @return string Sitemap XML contents. */ protected function output_sitemap_content() { $this->the_seo_framework_debug and $timer_start = microtime( true ); /** * Re-use the variable, eliminating database requests * @since 2.4.0 */ $sitemap_content = $this->is_option_checked( 'cache_sitemap' ) ? $this->get_transient( $this->sitemap_transient ) : false; echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; echo $this->get_sitemap_xsl_stylesheet_tag(); /** * Output debug prior output. * @since 2.8.0 */ if ( $this->the_seo_framework_debug ) { echo '<!-- Site estimated peak usage prior to generation: ' . number_format( memory_get_peak_usage() / 1024 / 1024, 3 ) . ' MB -->' . "\n"; echo '<!-- System estimated peak usage prior to generation: ' . number_format( memory_get_peak_usage( true ) / 1024 / 1024, 3 ) . ' MB -->' . "\n"; } echo $this->get_sitemap_urlset_open_tag(); echo $this->setup_sitemap( $sitemap_content ); echo $this->get_sitemap_urlset_close_tag(); if ( false === $sitemap_content ) { echo "\n" . '<!-- ' . \esc_html__( 'Sitemap is generated for this view', 'autodescription' ) . ' -->'; } else { echo "\n" . '<!-- ' . \esc_html__( 'Sitemap is served from cache', 'autodescription' ) . ' -->'; } /** * Output debug info. * @since 2.3.7 */ if ( $this->the_seo_framework_debug ) { echo "\n" . '<!-- Site estimated peak usage: ' . number_format( memory_get_peak_usage() / 1024 / 1024, 3 ) . ' MB -->'; echo "\n" . '<!-- System estimated peak usage: ' . number_format( memory_get_peak_usage( true ) / 1024 / 1024, 3 ) . ' MB -->'; echo "\n" . '<!-- Freed memory prior to generation: ' . number_format( $this->clean_up_globals_for_sitemap( true ) / 1024, 3 ) . ' kB -->'; echo "\n" . '<!-- Sitemap generation time: ' . number_format( microtime( true ) - $timer_start, 6 ) . ' seconds -->'; } } /** * Returns the opening tag for the sitemap URLset. * * @since 2.8.0 * * @return string The sitemap URLset opening tag. */ public function get_sitemap_urlset_open_tag() { $schemas = array( 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', 'xmlns:xhtml' => 'http://www.w3.org/1999/xhtml', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => array( 'http://www.sitemaps.org/schemas/sitemap/0.9', 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd', ), ); /** * Applies filters 'the_seo_framework_sitemap_schemas' : array * @since 2.8.0 * @param array $schems The schema list. URLs are expected to be escaped. */ $schemas = (array) \apply_filters( 'the_seo_framework_sitemap_schemas', $schemas ); $urlset = '<urlset'; foreach ( $schemas as $type => $values ) { $urlset .= ' ' . $type . '="'; if ( is_array( $values ) ) { $urlset .= implode( ' ', $values ); } else { $urlset .= $values; } $urlset .= '"'; } $urlset .= '>'; return $urlset . "\n"; } /** * Returns the closing tag for the sitemap URLset. * * @since 2.8.0 * * @return string The sitemap URLset closing tag. */ public function get_sitemap_urlset_close_tag() { return '</urlset>'; } /** * Returns stylesheet XSL location tag. * * @since 2.8.0 * @since 2.9.3 Now checks against request to see if there's a domain mismatch. * * @return string The sitemap XSL location tag. */ public function get_sitemap_xsl_stylesheet_tag() { if ( $this->is_option_checked( 'sitemap_styles' ) ) { $url = \esc_url( $this->get_sitemap_xsl_url(), array( 'http', 'https' ) ); if ( ! empty( $_SERVER['HTTP_HOST'] ) ) { $_parsed = \wp_parse_url( $url ); $_r_parsed = \wp_parse_url( \esc_url( \wp_unslash( $_SERVER['HTTP_HOST'] ), array( 'http', 'https' ) ) ); if ( isset( $_parsed['host'] ) && isset( $_r_parsed['host'] ) ) if ( $_parsed['host'] !== $_r_parsed['host'] ) return ''; } return sprintf( '<?xml-stylesheet type="text/xsl" href="%s"?>', $url ) . "\n"; } return ''; } /** * Returns the stylesheet XSL location URL. * * @since 2.8.0 * @since 3.0.0 1: No longer uses home URL from cache. But now uses `get_home_url()`. * 2: Now takes query parameters (if any) and restores them correctly. * @global object $wp_rewrite * * @return string URL location of the XSL stylesheet. Unescaped. */ public function get_sitemap_xsl_url() { global $wp_rewrite; $home = $this->set_url_scheme( \get_home_url() ); $parsed = parse_url( $home ); $query = isset( $parsed['query'] ) ? $parsed['query'] : ''; if ( $query ) $home = str_replace( '?' . $query, '', $home ); $home = \trailingslashit( $home ); if ( $wp_rewrite->using_index_permalinks() ) { $loc = $home . 'index.php/sitemap.xsl'; } elseif ( $wp_rewrite->using_permalinks() ) { $loc = $home . 'sitemap.xsl'; } else { $loc = $home . '?the_seo_framework_sitemap=xsl'; } if ( $query ) $loc = $this->append_php_query( $loc, $query ); return $loc; } /** * Returns the sitemap XML location URL. * * @since 2.9.2 * @since 3.0.0 1: No longer uses home URL from cache. But now uses `get_home_url()`. * 2: Now takes query parameters (if any) and restores them correctly. * @global object $wp_rewrite * * @return string URL location of the XML sitemap. Unescaped. */ public function get_sitemap_xml_url() { global $wp_rewrite; $home = $this->set_url_scheme( \get_home_url() ); $parsed = parse_url( $home ); $query = isset( $parsed['query'] ) ? $parsed['query'] : ''; if ( $query ) $home = str_replace( '?' . $query, '', $home ); $home = \trailingslashit( $home ); if ( $query ) $home = str_replace( '?' . $query, '', $home ); if ( $wp_rewrite->using_index_permalinks() ) { $loc = $home . 'index.php/sitemap.xml'; } elseif ( $wp_rewrite->using_permalinks() ) { $loc = $home . 'sitemap.xml'; } else { $loc = $home . '?the_seo_framework_sitemap=xml'; } if ( $query ) $loc = $this->append_php_query( $loc, $query ); return $loc; } /** * Returns the robots.txt location URL. * Only allows root domains. * * @since 2.9.2 * @global object $wp_rewrite * * @return string URL location of robots.txt. Unescaped. */ public function get_robots_txt_url() { global $wp_rewrite; if ( $wp_rewrite->using_permalinks() && ! $this->is_subdirectory_installation() ) { $home = \trailingslashit( $this->set_url_scheme( $this->get_home_host() ) ); $loc = $home . 'robots.txt'; } else { $loc = ''; } return $loc; } /** * Sitemap XSL stylesheet output. * * @since 2.8.0 */ public function output_sitemap_xsl_stylesheet() { $this->clean_response_header(); if ( ! headers_sent() ) { header( 'Content-type: text/xsl; charset=utf-8' ); header( 'Cache-Control: max-age=1800' ); } $this->get_view( 'sitemap/xsl-stylesheet' ); exit; } /** * Create sitemap.xml content transient. * * @since 2.6.0 * @since 3.0.6 Now only sets transient when the option is checked. * * @param string|bool $content required The sitemap transient content. * @return string The sitemap content. */ public function setup_sitemap( $sitemap_content = false ) { if ( false === $sitemap_content ) { //* Transient doesn't exist yet. $sitemap_content = $this->generate_sitemap(); /** * Transient expiration: 1 week. * Keep the sitemap for at most 1 week. */ $expiration = WEEK_IN_SECONDS; if ( $this->is_option_checked( 'cache_sitemap' ) ) $this->set_transient( $this->sitemap_transient, $sitemap_content, $expiration ); } return $sitemap_content; } /** * Generate sitemap.xml content. * * @since 2.2.9 * @since 2.8.0 Now adjusts memory limit when possible. * @since 2.9.3 No longer crashes on WordPress sites below WP 4.6. * @since 3.0.4 No longer outputs empty URL entries. * * @return string The sitemap content. */ protected function generate_sitemap() { function_exists( '\wp_is_ini_value_changeable' ) and \wp_is_ini_value_changeable( 'memory_limit' ) and @ini_set( 'memory_limit', WP_MAX_MEMORY_LIMIT ); $content = ''; /** * Maximum pages and posts to fetch. * A total of 2100, consisting of 3 times $max_posts * * @since 2.2.9 * * Applies filters the_seo_framework_sitemap_pages_count : int max pages * Applies filters the_seo_framework_sitemap_posts_count : int max posts * Applies filters the_seo_framework_sitemap_custom_posts_count : int max posts */ $totalpages = (int) \apply_filters( 'the_seo_framework_sitemap_pages_count', $this->max_posts ); $totalposts = (int) \apply_filters( 'the_seo_framework_sitemap_posts_count', $this->max_posts ); $total_cpt_posts = (int) \apply_filters( 'the_seo_framework_sitemap_custom_posts_count', $this->max_posts ); $latest_pages = array(); $latest_posts = array(); $latest_cpt_posts = array(); $cpt = array(); //* Sets timezone according to WordPress settings. $this->set_timezone(); $timestamp_format = $this->get_timestamp_format(); /** * Fetch the page/post modified options. * We can't get specific on the home page, unfortunately. */ $sitemaps_modified = $this->is_option_checked( 'sitemaps_modified' ); $page_lastmod = $post_lastmod = $home_lastmod = (bool) $sitemaps_modified; /** * Generation time output * * Applies filter the_seo_framework_sitemap_timestamp : bool */ $timestamp = (bool) \apply_filters( 'the_seo_framework_sitemap_timestamp', true ); if ( $timestamp ) $content .= '<!-- ' . \esc_html__( 'Sitemap is generated on', 'autodescription' ) . ' ' . \current_time( 'Y-m-d H:i:s' ) . ' GMT -->' . "\n"; $wp_query = new \WP_Query; $wp_query->init(); $query = $wp_query->query = $wp_query->query_vars = array(); if ( $totalpages ) { //* Ascend by the date for normal pages. Older pages get to the top of the list. $defaults = array( 'posts_per_page' => $totalpages, 'post_type' => 'page', 'orderby' => 'date', 'order' => 'ASC', 'post_status' => 'publish', 'has_password' => false, 'fields' => 'ids', 'cache_results' => false, 'suppress_filters' => false, 'no_found_rows' => true, ); /** * Applies filters 'the_seo_framework_sitemap_pages_query_args' : array * * @since 2.8.0 * @since 3.0.6: $args['suppress_filters'] now defaults to false. * * @param array $args The new query arguments. * @param array $defaults The default query arguments */ $args = \apply_filters( 'the_seo_framework_sitemap_pages_query_args', array(), $defaults ); $wp_query->query = $wp_query->query_vars = \wp_parse_args( $args, $defaults ); $latest_pages = $wp_query->get_posts(); } $latest_pages_amount = count( $latest_pages ); if ( $latest_pages_amount > 0 ) : $page_on_front = $this->has_page_on_front(); $page_on_front_id = (int) \get_option( 'page_on_front' ); $page_for_posts_id = (int) \get_option( 'page_for_posts' ); $id_on_front = $page_on_front ? $page_on_front_id : $page_for_posts_id; //* Remove ID on front from list and add frontpage to list. if ( $page_on_front && false !== $key_on_front = array_search( $id_on_front, $latest_pages, true ) ) { unset( $latest_pages[ $key_on_front ] ); } //= Render frontpage. $front_page = $page_on_front ? \get_post( $id_on_front ) : null; $render_front = false; if ( ! $this->get_option( 'homepage_noindex' ) ) { if ( $page_on_front ) { $render_front = isset( $front_page->ID ) && $this->is_post_included_in_sitemap( $front_page->ID ) && ! $this->is_protected( $front_page->ID ); } else { $render_front = $this->is_post_included_in_sitemap( $id_on_front ); } } if ( $render_front ) { $_url = $this->get_homepage_permalink(); if ( $_url ) { $content .= "\t<url>\n"; $content .= "\t\t<loc>" . $_url . "</loc>\n"; // Keep it consistent. Only parse if page_lastmod is true. if ( $home_lastmod ) { if ( $page_on_front ) { $front_modified_gmt = isset( $front_page->post_modified_gmt ) ? $front_page->post_modified_gmt : '0000-00-00 00:00:00'; } else { $args = array( 'numberposts' => 1, 'post_type' => 'post', 'post_status' => 'publish', 'has_password' => false, 'orderby' => 'post_date', 'order' => 'DESC', 'offset' => 0, ); $latests_posts = \wp_get_recent_posts( $args, OBJECT ); $latest_post = isset( $latests_posts[0] ) ? $latests_posts[0] : null; $front_modified_gmt = isset( $latest_post->post_date_gmt ) ? $latest_post->post_date_gmt : '0000-00-00 00:00:00'; } if ( '0000-00-00 00:00:00' !== $front_modified_gmt ) $content .= "\t\t<lastmod>" . $this->gmt2date( $timestamp_format, $front_modified_gmt ) . "</lastmod>\n"; } $content .= "\t\t<priority>1.0</priority>\n"; $content .= "\t</url>\n"; } //* Free memory. unset( $latests_posts, $latest_post, $front_page ); } //= Render the page for posts. if ( $page_on_front && $page_for_posts_id ) : //* Remove ID for blog from list and add frontpage to list. if ( false !== $key_for_posts = array_search( $page_for_posts_id, $latest_pages, true ) ) { unset( $latest_pages[ $key_for_posts ] ); } $blog_page = \get_post( $page_for_posts_id ); $render_blog = isset( $blog_page->ID ) && $this->is_post_included_in_sitemap( $blog_page->ID ) && ! $this->is_protected( $blog_page->ID ); if ( $render_blog ) { $_url = $this->create_canonical_url( array( 'id' => $blog_page->ID ) ); if ( $_url ) { $content .= "\t<url>\n"; $content .= "\t\t<loc>" . $_url . "</loc>\n"; // Keep it consistent. Only parse if $page_lastmod is true. if ( $page_lastmod ) { $args = array( 'numberposts' => 1, 'post_type' => 'post', 'post_status' => 'publish', 'has_password' => false, 'orderby' => 'post_date', 'order' => 'DESC', 'offset' => 0, ); $lastest_posts = \wp_get_recent_posts( $args, OBJECT ); $lastest_post = isset( $lastest_posts[0] ) ? $lastest_posts[0] : null; $latest_post_published_gmt = isset( $lastest_post->post_date_gmt ) ? $lastest_post->post_date_gmt : '0000-00-00 00:00:00'; $page_for_posts_modified_gmt = $blog_page->post_modified_gmt; if ( strtotime( $latest_post_published_gmt ) > strtotime( $page_for_posts_modified_gmt ) ) { $page_modified_gmt = $latest_post_published_gmt; } else { $page_modified_gmt = $page_for_posts_modified_gmt; } if ( '0000-00-00 00:00:00' !== $page_modified_gmt ) $content .= "\t\t<lastmod>" . $this->gmt2date( $timestamp_format, $page_modified_gmt ) . "</lastmod>\n"; } $content .= "\t\t<priority>0.9</priority>\n"; $content .= "\t</url>\n"; } } //* Free memory. unset( $latest_posts, $latest_post, $blog_page ); endif; foreach ( $latest_pages as $page_id ) : $page = \get_post( $page_id ); if ( empty( $page->ID ) || ! $this->is_post_included_in_sitemap( $page->ID ) ) continue; $_url = $this->create_canonical_url( array( 'id' => $page->ID ) ); if ( ! $_url ) continue; $content .= "\t<url>\n"; $content .= "\t\t<loc>" . $_url . "</loc>\n"; // Keep it consistent. Only parse if page_lastmod is true. if ( $page_lastmod ) { $page_modified_gmt = $page->post_modified_gmt; if ( '0000-00-00 00:00:00' !== $page_modified_gmt ) $content .= "\t\t<lastmod>" . $this->gmt2date( $timestamp_format, $page_modified_gmt ) . "</lastmod>\n"; } $content .= "\t\t<priority>0.9</priority>\n"; $content .= "\t</url>\n"; endforeach; //* Free memory. unset( $latest_pages, $page ); endif; if ( $totalposts ) { //* Descend by the date for posts. The latest posts get to the top of the list after pages. $defaults = array( 'posts_per_page' => $totalposts, 'post_type' => 'post', 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', 'has_password' => false, 'fields' => 'ids', 'cache_results' => false, 'suppress_filters' => false, 'no_found_rows' => true, ); /** * Applies filters 'the_seo_framework_sitemap_posts_query_args' : array * * @since 2.8.0 * @since 3.0.6: $args['suppress_filters'] now defaults to false. * * @param array $args The new query arguments. * @param array $defaults The default query arguments */ $args = \apply_filters( 'the_seo_framework_sitemap_posts_query_args', array(), $defaults ); $wp_query->query = $wp_query->query_vars = \wp_parse_args( $args, $defaults ); $latest_posts = $wp_query->get_posts(); } $latest_posts_amount = count( $latest_posts ); if ( $latest_posts_amount > 0 ) : /** * Setting up priorities, with pages always being important. * * From there, older posts get a gradually lower priority. Down to 0. * Differentiate with 1 / max posts (0 to $this->max_posts). With a 1 dot decimal. */ $priority = 0.9; /** * Infinity is abstract. But what is it when it's both positive and negative? * Undefined. Bugfix. * * @since 2.3.2 * @thanks Schlock | https://wordpress.org/support/topic/sitemap-xml-parsing-error */ $prioritydiff = 0; if ( $latest_posts_amount > 1 ) $prioritydiff = 0.9 / $latest_posts_amount; // Keep it consistent. Only remove 0.1 when we only have a few posts. if ( $latest_posts_amount <= 9 && $latest_posts_amount > 1 ) $prioritydiff = 0.1; /** * This can be heavy. */ foreach ( $latest_posts as $post_id ) : $post = \get_post( $post_id ); if ( empty( $post->ID ) || ! $this->is_post_included_in_sitemap( $post->ID ) ) continue; $_url = $this->create_canonical_url( array( 'id' => $post->ID ) ); if ( ! $_url ) continue; $content .= "\t<url>\n"; // No need to use static vars $content .= "\t\t<loc>" . $_url . "</loc>\n"; // Keep it consistent. Only parse if page_lastmod is true. if ( $post_lastmod ) { $post_modified_gmt = $post->post_modified_gmt; if ( '0000-00-00 00:00:00' !== $post_modified_gmt ) $content .= "\t\t<lastmod>" . $this->gmt2date( $timestamp_format, $post_modified_gmt ) . "</lastmod>\n"; } $content .= "\t\t<priority>" . number_format( $priority, 1 ) . "</priority>\n"; $content .= "\t</url>\n"; // Lower the priority for the next pass. $priority = $priority - $prioritydiff; // Cast away negative numbers. $priority = $priority <= 0 ? 0 : (float) $priority; endforeach; //* Free memory. unset( $latest_posts, $post ); endif; if ( $total_cpt_posts ) : $post_page = (array) \get_post_types( array( 'public' => true ) ); /** * Applies filters Array the_seo_framework_sitemap_exclude_cpt : Excludes these CPT * @since 2.5.0 */ $excluded_cpt = (array) \apply_filters( 'the_seo_framework_sitemap_exclude_cpt', array() ); $not_cpt = array( 'post', 'page', 'attachment' ); foreach ( $post_page as $post_type ) { if ( false === in_array( $post_type, $not_cpt, true ) ) { if ( empty( $excluded_cpt ) || false === in_array( $post_type, $excluded_cpt, true ) ) { if ( $this->post_type_supports_custom_seo( $post_type ) ) { $cpt[] = $post_type; } } } } if ( $cpt ) { //* Descend by the date for CPTs. The latest posts get to the top of the list after pages. $defaults = array( 'posts_per_page' => $total_cpt_posts, 'post_type' => $cpt, 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', 'has_password' => false, 'fields' => 'ids', 'cache_results' => false, 'suppress_filters' => false, 'no_found_rows' => true, ); /** * Applies filters 'the_seo_framework_sitemap_cpt_query_args' : array * * @since 2.8.0 * @since 3.0.6: $args['suppress_filters'] now defaults to false. * * @param array $args The new query arguments. * @param array $defaults The default query arguments */ $args = \apply_filters( 'the_seo_framework_sitemap_cpt_query_args', array(), $defaults ); $wp_query->query = $wp_query->query_vars = \wp_parse_args( $args, $defaults ); $latest_cpt_posts = $wp_query->get_posts(); } endif; $latest_cpt_posts_amount = count( $latest_cpt_posts ); if ( $latest_cpt_posts_amount > 0 ) : /** * Setting up priorities, with pages always being important. * * From there, older posts get a gradually lower priority. Down to 0. * Differentiate with 1 / max posts (0 to $this->max_posts). With a 1 dot decimal. */ $priority_cpt = 0.9; $prioritydiff_cpt = 0; if ( $latest_cpt_posts_amount > 1 ) $prioritydiff_cpt = 0.9 / $latest_cpt_posts_amount; // Keep it consistent. Only remove 0.1 when we only have a few posts. if ( $latest_cpt_posts_amount <= 9 && $latest_cpt_posts_amount > 1 ) $prioritydiff_cpt = 0.1; /** * This can be heavy. */ foreach ( $latest_cpt_posts as $ctp_post_id ) : $ctp_post = \get_post( $ctp_post_id ); if ( empty( $ctp_post->ID ) || ! $this->is_post_included_in_sitemap( $ctp_post->ID ) ) continue; $_url = $this->create_canonical_url( array( 'id' => $ctp_post->ID ) ); if ( ! $_url ) continue; $content .= "\t<url>\n"; //* No need to use static vars $content .= "\t\t<loc>" . $_url . "</loc>\n"; //* Keep it consistent. Only parse if $post_lastmod is true. if ( $post_lastmod ) { $cpt_modified_gmt = $ctp_post->post_modified_gmt; //* Some CPT don't set modified time. if ( '0000-00-00 00:00:00' !== $cpt_modified_gmt ) $content .= "\t\t<lastmod>" . $this->gmt2date( $timestamp_format, $cpt_modified_gmt ) . "</lastmod>\n"; } $content .= "\t\t<priority>" . number_format( $priority_cpt, 1 ) . "</priority>\n"; $content .= "\t</url>\n"; // Lower the priority for the next pass. $priority_cpt = $priority_cpt - $prioritydiff_cpt; // Cast away negative numbers. $priority_cpt = $priority_cpt <= 0 ? 0 : (float) $priority_cpt; endforeach; //* Free memory. unset( $latest_cpt_posts, $ctp_post ); endif; /** * Applies filters the_seo_framework_sitemap_additional_urls : * * @since 2.5.2 * @param array $custom_urls : { * @param string (key) $url The absolute url to the page. : array { * @param string $lastmod UNIXTIME Last modified date, e.g. "2016-01-26 13:04:55" * @param float|int|string $priority URL Priority * } * } * * @example return value: [ 'http://example.com' => [ 'lastmod' => '14-01-2018', 'priority' => 0.9 ] ] */ $custom_urls = (array) \apply_filters( 'the_seo_framework_sitemap_additional_urls', array() ); if ( $custom_urls ) { //* Force ent2ncr to run, regardless of filters. \remove_all_filters( 'pre_ent2ncr', false ); foreach ( $custom_urls as $url => $args ) { if ( ! is_array( $args ) ) { //* If there are no args, it's assigned as URL (per example) $url = $args; } $content .= "\t<url>\n"; //* No need to use static vars $content .= "\t\t<loc>" . \ent2ncr( \esc_url_raw( $url, array( 'http', 'https' ) ) ) . "</loc>\n"; if ( isset( $args['lastmod'] ) && $args['lastmod'] ) { $content .= "\t\t<lastmod>" . \mysql2date( $timestamp_format, $args['lastmod'], false ) . "</lastmod>\n"; } if ( isset( $args['priority'] ) && $args['priority'] ) { $priority = $args['priority']; } else { $priority = 0.9; } $content .= "\t\t<priority>" . number_format( $priority, 1 ) . "</priority>\n"; $content .= "\t</url>\n"; } } /** * Applies filters the_seo_framework_sitemap_extend : string * @since 2.5.2 */ $extend = (string) \apply_filters( 'the_seo_framework_sitemap_extend', '' ); if ( $extend ) $content .= "\t" . $extend . "\n"; //* Reset timezone to default. $this->reset_timezone(); return $content; } /** * Determines if post is possibly included in the sitemap. * * This is a weak check, as the filter might not be present outside of the * sitemap's scope. * The URL also isn't checked, nor the position. * * @since 3.0.4 * @since 3.1.0 : First filter value now works as intended. * * @param int $id The post ID to check. When 0, the custom field will not be checked. * @return bool True if included, false otherwise. */ public function is_post_included_in_sitemap( $id ) { static $excluded = null; if ( null === $excluded ) { /** * Applies filters the_seo_framework_sitemap_exclude_ids : sequential array of id's * * @since 2.5.2 * @since 2.8.0 : No longer accepts '0' as entry. */ $excluded = (array) \apply_filters( 'the_seo_framework_sitemap_exclude_ids', array() ); if ( empty( $excluded ) ) { $excluded = array(); } else { $excluded = array_flip( $excluded ); } } if ( ! isset( $excluded[ $id ] ) && $id ) { $included = ! $this->get_custom_field( '_genesis_noindex', $id ); } return $included; } /** * Ping search engines on post publish. * * @since 2.2.9 * @global int $blog_id * * @return void Early if blog is not public. */ public function ping_searchengines() { if ( $this->is_option_checked( 'site_noindex' ) || $this->is_blog_public() ) return; $transient = 'tsf_throttle_ping_' . $GLOBALS['blog_id']; //* NOTE: Use legacy get_transient to prevent ping spam. if ( false === \get_transient( $transient ) ) { //* Transient doesn't exist yet. if ( $this->is_option_checked( 'ping_google' ) ) $this->ping_google(); if ( $this->is_option_checked( 'ping_bing' ) ) $this->ping_bing(); if ( $this->is_option_checked( 'ping_yandex' ) ) $this->ping_yandex(); // Sorry, I couldn't help myself. $throttle = 'Bert and Ernie are weird.'; /** * Limit the pinging to a maximum of 1 per hour. * Transient expiration. 1 hour. * * Applies filters the_seo_framework_sitemap_throttle_s * @since 2.5.1 */ $expiration = (int) \apply_filters( 'the_seo_framework_sitemap_throttle_s', HOUR_IN_SECONDS ); //* @NOTE: Using legacy set_transient to prevent ping spam. \set_transient( $transient, $throttle, $expiration ); } } /** * Ping Google * * @since 2.2.9 */ public function ping_google() { $pingurl = 'http://www.google.com/webmasters/sitemaps/ping?sitemap=' . urlencode( $this->get_sitemap_xml_url() ); \wp_safe_remote_get( $pingurl, array( 'timeout' => 3 ) ); } /** * Ping Bing * * @since 2.2.9 */ public function ping_bing() { $pingurl = 'http://www.bing.com/webmaster/ping.aspx?siteMap=' . urlencode( $this->get_sitemap_xml_url() ); \wp_safe_remote_get( $pingurl, array( 'timeout' => 3 ) ); } /** * Ping Yandex * * @since 2.6.0 */ public function ping_yandex() { $pingurl = 'http://blogs.yandex.ru/pings/?status=success&url=' . urlencode( $this->get_sitemap_xml_url() ); \wp_safe_remote_get( $pingurl, array( 'timeout' => 3 ) ); } /** * Initialize and flush rewrite rules. * * @since 2.6.0 * @since 2.8.0 : Deprecated? * @access private * @deprecated silently. */ public function flush_rewrite_rules() { global $wp_rewrite; $this->rewrite_rule_sitemap(); \flush_rewrite_rules(); } /** * Enqueues rewrite rules flush. * * @since 2.8.0 */ public function reinitialize_rewrite() { if ( $this->get_option( 'sitemaps_output', false ) ) { $this->rewrite_rule_sitemap(); $this->enqueue_rewrite_activate( true ); } else { $this->enqueue_rewrite_deactivate( true ); } } /** * Enqueue rewrite flush for activation. * * @since 2.3.0 * @access private * @staticvar bool $flush Only true * * @param bool $enqueue Whether to enqueue the flush or return its state. * * @return bool Whether to flush. */ public function enqueue_rewrite_activate( $enqueue = false ) { static $flush = null; if ( isset( $flush ) ) return $flush; if ( $enqueue ) return $flush = true; return false; } /** * Enqueue rewrite flush for deactivation. * * @since 2.3.0 * @access private * @staticvar bool $flush Only true * * @param bool $enqueue Whether to enqueue the flush or return its state. * * @return bool Whether to flush. */ public function enqueue_rewrite_deactivate( $enqueue = false ) { static $flush = null; if ( isset( $flush ) ) return $flush; if ( $enqueue ) return $flush = true; return false; } /** * Enqueue rewrite flush for deactivation. * * @since 2.6.0 * @access private * @staticvar bool $flush Only true * * @param bool $enqueue Whether to enqueue the flush or return its state. * * @return bool Whether to flush. */ public function enqueue_rewrite_flush_other( $enqueue = false ) { static $flush = null; if ( isset( $flush ) ) return $flush; if ( $enqueue ) return $flush = true; return false; } /** * Flush rewrite rules based on static variables. * * @since 2.3.0 * @access private */ public function maybe_flush_rewrite() { if ( $this->enqueue_rewrite_activate() ) $this->flush_rewrite_rules_activation(); if ( $this->enqueue_rewrite_deactivate() ) $this->flush_rewrite_rules_deactivation(); if ( $this->enqueue_rewrite_flush_other() ) $this->flush_rewrite_rules(); } /** * Add and Flush rewrite rules on plugin settings change. * * @since 2.6.6.1 * @access private */ public function flush_rewrite_rules_activation() { //* This function is called statically. $this->rewrite_rule_sitemap( true ); \flush_rewrite_rules(); } /** * Flush rewrite rules on settings change. * * @since 2.6.6.1 * @access private * @global object $wp_rewrite */ public function flush_rewrite_rules_deactivation() { global $wp_rewrite; $wp_rewrite->init(); unset( $wp_rewrite->extra_rules_top['sitemap\.xml$'] ); $wp_rewrite->flush_rules( true ); } /** * Returns sitemap color scheme. * * @since 2.8.0 * * @param bool $get_defaults Whether to get the default colors. * @return array The sitemap colors. */ public function get_sitemap_colors( $get_defaults = false ) { if ( $get_defaults ) { $retval = array( 'main' => '#333', 'accent' => '#00cd98', ); } else { $main = $this->s_color_hex( $this->get_option( 'sitemap_color_main' ) ); $accent = $this->s_color_hex( $this->get_option( 'sitemap_color_accent' ) ); $options = array( 'main' => $main ? '#' . $main : '', 'accent' => $accent ? '#' . $accent : '', ); $options = array_filter( $options ); $retval = array_merge( $this->get_sitemap_colors( true ), $options ); } return $retval; } }