Commit realizado el 12:13:52 08-04-2024

This commit is contained in:
Pagina Web Monito
2024-04-08 12:13:55 -04:00
commit 0c33094de9
7815 changed files with 1365694 additions and 0 deletions

View File

@@ -0,0 +1,312 @@
<?php
/**
* The sitemap provider for author archives.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Sitemap
* @author Rank Math <support@rankmath.com>
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
namespace RankMath\Sitemap\Providers;
use DateTime;
use DateTimeZone;
use RankMath\Helper;
use RankMath\Sitemap\Router;
use RankMath\Sitemap\Sitemap;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Author class.
*/
class Author implements Provider {
use Hooker;
/**
* Holds the Sitemap slug.
*
* @var string
*/
protected $sitemap_slug = null;
/**
* The constructor.
*/
public function __construct() {
$this->sitemap_slug = Router::get_sitemap_slug( 'author' );
$this->filter( 'rank_math/sitemap/author/query', 'exclude_users', 5 );
$this->filter( 'rank_math/sitemap/author/query', 'exclude_roles', 5 );
$this->filter( 'rank_math/sitemap/author/query', 'exclude_post_types', 5 );
}
/**
* Check if provider supports given item type.
*
* @param string $type Type string to check for.
* @return boolean
*/
public function handles_type( $type ) {
return $this->sitemap_slug === $type && Helper::get_settings( 'sitemap.authors_sitemap' );
}
/**
* Get set of sitemaps index link data.
*
* @param int $max_entries Entries per sitemap.
* @return array
*/
public function get_index_links( $max_entries ) {
if ( ! Helper::get_settings( 'sitemap.authors_sitemap' ) ) {
return [];
}
$users = $this->get_index_users();
if ( empty( $users ) ) {
return [];
}
$page = 1;
$index = [];
$user_pages = array_chunk( $users, $max_entries );
if ( 1 === count( $user_pages ) ) {
$page = '';
}
foreach ( $user_pages as $user_page ) {
$user = array_shift( $user_page ); // Time descending, first user on page is most recently updated.
$item = $this->do_filter(
'sitemap/index/entry',
[
'loc' => Router::get_base_url( $this->sitemap_slug . '-sitemap' . $page . '.xml' ),
'lastmod' => '@' . $user->last_update,
],
'author',
$user
);
if ( ! $item ) {
continue;
}
$index[] = $item;
$page++;
}
return $index;
}
/**
* Get set of sitemap link data.
*
* @param string $type Sitemap type.
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
* @return array
*/
public function get_sitemap_links( $type, $max_entries, $current_page ) {
$links = [];
if ( $current_page < 1 ) {
$current_page = 1;
}
$users = $this->get_users(
[
'offset' => ( $current_page - 1 ) * $max_entries,
'number' => $max_entries,
]
);
if ( empty( $users ) ) {
return $links;
}
Sitemap::maybe_redirect( count( $users ), $max_entries );
foreach ( $users as $user ) {
$url = $this->get_sitemap_url( $user );
if ( ! empty( $url ) ) {
$links[] = $url;
}
}
return $links;
}
/**
* Get sitemap urlset.
*
* @param WP_User $user User instance.
*
* @return bool|array
*/
private function get_sitemap_url( $user ) {
$author_link = get_author_posts_url( $user->ID );
if ( empty( $author_link ) ) {
return false;
}
$mod = isset( $user->last_update ) ? $user->last_update : strtotime( $user->user_registered );
$date = new DateTime();
$date->setTimestamp( $mod );
$date->setTimezone( new DateTimeZone( 'UTC' ) );
$url = [
'loc' => $author_link,
'mod' => $date->format( DATE_W3C ),
];
/** This filter is documented at includes/modules/sitemap/providers/class-post-type.php */
return $this->do_filter( 'sitemap/entry', $url, 'user', $user );
}
/**
* Retrieve users, taking account of all necessary exclusions.
*
* @param array $args Arguments to add.
* @return array
*/
public function get_users( $args = [] ) {
$defaults = [
'orderby' => 'meta_value_num',
'order' => 'DESC',
'meta_query' => [
'relation' => 'AND',
[
'relation' => 'OR',
[
'key' => 'last_update',
],
[
'key' => 'last_update',
'compare' => 'NOT EXISTS',
],
],
[
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
],
];
$args = $this->do_filter( 'sitemap/author/query', wp_parse_args( $args, $defaults ) );
return get_users( $args );
}
/**
* Exclude users.
*
* @param array $args Array of user query arguments.
*
* @return array
*/
public function exclude_users( $args ) {
$exclude = Helper::get_settings( 'sitemap.exclude_users' );
if ( ! empty( $exclude ) ) {
$args['exclude'] = wp_parse_id_list( $exclude );
}
return $args;
}
/**
* Exclude roles.
*
* @param array $args Array of user query arguments.
*
* @return array
*/
public function exclude_roles( $args ) {
$exclude_roles = Helper::get_settings( 'sitemap.exclude_roles' );
if ( ! empty( $exclude_roles ) ) {
$args['role__not_in'] = $exclude_roles;
}
return $args;
}
/**
* Exclude post types.
*
* @param array $args Array of user query arguments.
*
* @return array
*/
public function exclude_post_types( $args ) {
// Exclude post types.
$public_post_types = get_post_types( [ 'public' => true ] );
// We're not supporting sitemaps for author pages for attachments.
unset( $public_post_types['attachment'] );
$args['has_published_posts'] = array_keys( $public_post_types );
return $args;
}
/**
* Get all users according to author sitemap settings.
*
* @return array
*/
private function get_index_users() {
global $wpdb;
$exclude_users = Helper::get_settings( 'sitemap.exclude_users' );
$exclude_roles = Helper::get_settings( 'sitemap.exclude_roles' );
$exclude_users_query = ! $exclude_users ? '' : 'AND post_author NOT IN ( ' . esc_sql( $exclude_users ) . ' )';
$exclude_roles_query = '';
$meta_query = "(
( um.meta_key = 'rank_math_robots' AND um.meta_value NOT LIKE '%noindex%' )
OR um.user_id IS NULL
)
AND ( umt1.meta_key = 'last_update' OR umt1.user_id IS NULL )
";
if ( $exclude_roles ) {
$exclude_roles_query = "AND ( umt.meta_key ='wp_capabilities' AND ( ";
foreach ( $exclude_roles as $key => $role ) {
$exclude_roles_query .= 0 === $key ? " umt.meta_value NOT LIKE '%" . esc_sql( $role ) . "%'" : " AND umt.meta_value NOT LIKE '%" . esc_sql( $role ) . "%'";
}
$exclude_roles_query .= ' ) )';
}
$meta_query .= $exclude_roles_query;
$sql = "
SELECT u.ID, umt1.meta_value as last_update
FROM {$wpdb->users} as u
LEFT JOIN {$wpdb->usermeta} AS um ON ( u.ID = um.user_id AND um.meta_key = 'rank_math_robots' )
LEFT JOIN {$wpdb->usermeta} AS umt ON ( u.ID = umt.user_id AND umt.meta_key = 'wp_capabilities' )
LEFT JOIN {$wpdb->usermeta} AS umt1 ON ( u.ID = umt1.user_id AND umt1.meta_key = 'last_update' )
WHERE ( {$meta_query} )
AND u.ID IN (
SELECT post_author
FROM {$wpdb->posts} as p
WHERE p.post_status = 'publish' AND p.post_password = ''
{$exclude_users_query}
)
ORDER BY umt1.meta_value DESC
";
return $wpdb->get_results( $sql ); // phpcs:ignore
}
}

View File

@@ -0,0 +1,575 @@
<?php
/**
* The sitemap provider for post types.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Sitemap
* @author Rank Math <support@rankmath.com>
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
namespace RankMath\Sitemap\Providers;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Sitemap\Router;
use RankMath\Sitemap\Sitemap;
use RankMath\Sitemap\Classifier;
use RankMath\Sitemap\Image_Parser;
defined( 'ABSPATH' ) || exit;
/**
* Post type provider class.
*/
class Post_Type implements Provider {
use Hooker;
/**
* Holds the `home_url()` value to speed up loops.
*
* @var string
*/
protected $home_url = null;
/**
* Holds image parser instance.
*
* @var Image_Parser
*/
protected $image_parser = null;
/**
* Holds link classifier.
*
* @var Classifier
*/
protected $classifier = null;
/**
* Static front page ID.
*
* @var int
*/
protected $page_on_front_id = null;
/**
* Posts page ID.
*
* @var int
*/
protected $page_for_posts_id = null;
/**
* Check if provider supports given item type.
*
* @param string $type Type string to check for.
*
* @return boolean
*/
public function handles_type( $type ) {
if (
false === post_type_exists( $type ) ||
! Helper::get_settings( 'sitemap.pt_' . $type . '_sitemap' ) ||
( 'attachment' === $type && Helper::get_settings( 'general.attachment_redirect_urls', true ) )
) {
return false;
}
/**
* Filter decision if post type is excluded from the XML sitemap.
*
* @param bool $exclude Default false.
* @param string $type Post type name.
*/
return ! $this->do_filter( 'sitemap/exclude_post_type', false, $type );
}
/**
* Get set of sitemaps index link data.
*
* @param int $max_entries Entries per sitemap.
*
* @return array
*/
public function get_index_links( $max_entries ) {
global $wpdb;
$post_types = Helper::get_accessible_post_types();
$post_types = array_filter( $post_types, [ $this, 'handles_type' ] );
$last_modified_times = Sitemap::get_last_modified_gmt( $post_types, true );
$index = [];
foreach ( $post_types as $post_type ) {
$total_count = $this->get_post_type_count( $post_type );
if ( 0 === $total_count ) {
continue;
}
$max_pages = 1;
if ( $total_count > $max_entries ) {
$max_pages = (int) ceil( $total_count / $max_entries );
}
$all_dates = [];
if ( $max_pages > 1 ) {
$sql = "
SELECT post_modified_gmt
FROM ( SELECT @rownum:=@rownum rownum, $wpdb->posts.post_modified_gmt
FROM ( SELECT @rownum:=0 ) r, $wpdb->posts
WHERE post_status IN ( 'publish', 'inherit' )
AND post_type = %s
ORDER BY post_modified_gmt ASC
)
x WHERE rownum %% %d = 0 ORDER BY post_modified_gmt DESC";
$all_dates = $wpdb->get_col( $wpdb->prepare( $sql, $post_type, $max_entries ) ); // phpcs:ignore
}
for ( $page_counter = 0; $page_counter < $max_pages; $page_counter++ ) {
$current_page = ( $max_pages > 1 ) ? ( $page_counter + 1 ) : '';
$date = false;
if ( isset( $all_dates[ $page_counter ] ) ) {
$date = $all_dates[ $page_counter ];
} elseif ( ! empty( $last_modified_times[ $post_type ] ) ) {
$date = $last_modified_times[ $post_type ];
}
$item = $this->do_filter(
'sitemap/index/entry',
[
'loc' => Router::get_base_url( $post_type . '-sitemap' . $current_page . '.xml' ),
'lastmod' => $date,
],
'post',
$post_type,
);
if ( ! $item ) {
continue;
}
$index[] = $item;
}
}
return $index;
}
/**
* Get set of sitemap link data.
*
* @param string $type Sitemap type.
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
*
* @return array
*/
public function get_sitemap_links( $type, $max_entries, $current_page ) {
$links = [];
$steps = $max_entries;
$offset = ( $current_page > 1 ) ? ( ( $current_page - 1 ) * $max_entries ) : 0;
$total = ( $offset + $max_entries );
$typecount = $this->get_post_type_count( $type );
Sitemap::maybe_redirect( $typecount, $max_entries );
if ( $total > $typecount ) {
$total = $typecount;
}
if ( 1 === $current_page ) {
$links = array_merge( $links, $this->get_first_links( $type ) );
}
if ( 0 === $typecount ) {
return $links;
}
$stacked_urls = [];
while ( $total > $offset ) {
$posts = $this->get_posts( $type, $steps, $offset );
$offset += $steps;
if ( empty( $posts ) ) {
continue;
}
foreach ( $posts as $post ) {
$post_id = (int) $post->ID;
if ( ! Sitemap::is_object_indexable( $post_id ) ) {
continue;
}
$url = $this->get_url( $post );
if ( ! isset( $url['loc'] ) ) {
continue;
}
/**
* Filter URL entry before it gets added to the sitemap.
*
* @param array $url Array of URL parts.
* @param string $type URL type.
* @param object $user Data object for the URL.
*/
$url = $this->do_filter( 'sitemap/entry', $url, 'post', $post );
if ( empty( $url ) ) {
continue;
}
$stacked_urls[] = $url['loc'];
if ( $post_id === $this->get_page_for_posts_id() || $post_id === $this->get_page_on_front_id() ) {
array_unshift( $links, $url );
continue;
}
$links[] = $url;
}
unset( $post, $url );
}
return $links;
}
/**
* Get count of posts for post type.
*
* @param string $post_types Post types to retrieve count for.
*
* @return int
*/
protected function get_post_type_count( $post_types ) {
global $wpdb;
$posts_to_exclude = 'page' === $post_types ? $this->get_blog_page_id() : '';
$post_status = 'attachment' === $post_types ? [ 'publish', 'inherit' ] : [ 'publish' ];
/**
* Filter to add a JOIN clause for get_post_type_count(post types) query.
*
* @param string $join SQL join clause, defaults to an empty string.
* @param array $post_types Post types.
*/
$join_filter = $this->do_filter( 'sitemap/post_count/join', '', $post_types );
/**
* Filter to add a WHERE clause for get_post_type_count(post types) query.
*
* @param string $where SQL WHERE query, defaults to an empty string.
* @param array $post_types Post types.
*/
$where_filter = $this->do_filter( 'sitemap/post_count/where', '', $post_types );
$sql = "SELECT COUNT( DISTINCT p.ID ) as count FROM {$wpdb->posts} as p
{$join_filter}
LEFT JOIN {$wpdb->postmeta} AS pm ON ( p.ID = pm.post_id AND pm.meta_key = 'rank_math_robots' )
WHERE (
( pm.meta_key = 'rank_math_robots' AND pm.meta_value NOT LIKE '%noindex%' ) OR
pm.post_id IS NULL
)
AND p.post_type = '{$post_types}' AND p.post_status IN ( '" . join( "', '", esc_sql( $post_status ) ) . "' ) AND p.post_password = ''
AND p.ID != '{$posts_to_exclude}'
{$where_filter}";
return (int) $wpdb->get_var( $sql ); // phpcs:ignore
}
/**
* Produces set of links to prepend at start of first sitemap page.
*
* @param string $post_type Post type to produce links for.
*
* @return array
*/
protected function get_first_links( $post_type ) {
$links = [];
$needs_archive = true;
if ( ! $this->get_page_on_front_id() && ( 'post' === $post_type || 'page' === $post_type ) ) {
$needs_archive = false;
$links[] = [
'loc' => $this->get_home_url(),
'mod' => Sitemap::get_last_modified_gmt( $post_type ),
];
} elseif ( $this->get_page_on_front_id() && 'post' === $post_type && $this->get_page_for_posts_id() ) {
$needs_archive = false;
$links[] = Sitemap::is_object_indexable( $this->get_page_for_posts_id() ) ? [ 'loc' => get_permalink( $this->get_page_for_posts_id() ) ] : '';
}
if ( ! $needs_archive ) {
return array_filter( $links );
}
$archive_url = $this->get_post_type_archive_link( $post_type );
/**
* Filter the URL Rank Math SEO uses in the XML sitemap for this post type archive.
*
* @param string $archive_url The URL of this archive
* @param string $post_type The post type this archive is for.
*/
$archive_url = $this->do_filter( 'sitemap/post_type_archive_link', $archive_url, $post_type );
if ( $archive_url ) {
$links[] = [
'loc' => $archive_url,
'mod' => Sitemap::get_last_modified_gmt( $post_type ),
];
}
return $links;
}
/**
* Get URL for a post type archive.
*
* @param string $post_type Post type.
*
* @return string|boolean URL or false if it should be excluded.
*/
protected function get_post_type_archive_link( $post_type ) {
// Post archive should be excluded if it isn't front page or posts page.
if ( 'post' === $post_type && get_option( 'show_on_front' ) !== 'posts' && ! $this->get_page_for_posts_id() ) {
return false;
}
return get_post_type_archive_link( $post_type );
}
/**
* Retrieve set of posts with optimized query routine.
*
* @param array $post_types Post type to retrieve.
* @param int $count Count of posts to retrieve.
* @param int $offset Starting offset.
*
* @return object[]
*/
protected function get_posts( $post_types, $count, $offset ) {
global $wpdb;
$posts_to_exclude = 'page' === $post_types ? $this->get_blog_page_id() : '';
$post_status = 'attachment' === $post_types ? [ 'publish', 'inherit' ] : [ 'publish' ];
/**
* Filter to add a JOIN clause for get_posts(types) query.
*
* @param string $join SQL join clause, defaults to an empty string.
* @param array $post_types Post types.
*/
$join_filter = $this->do_filter( 'sitemap/get_posts/join', '', $post_types );
/**
* Filter to add a WHERE clause for get_posts(types) query.
*
* @param string $where SQL WHERE query, defaults to an empty string.
* @param array $post_types Post types.
*/
$where_filter = $this->do_filter( 'sitemap/get_posts/where', '', $post_types );
$sql = "
SELECT l.ID, post_title, post_content, post_name, post_parent, post_author, post_modified_gmt, post_date, post_date_gmt, post_type
FROM (
SELECT DISTINCT p.ID FROM {$wpdb->posts} as p
{$join_filter}
LEFT JOIN {$wpdb->postmeta} AS pm ON ( p.ID = pm.post_id AND pm.meta_key = 'rank_math_robots' )
WHERE (
( pm.meta_key = 'rank_math_robots' AND pm.meta_value NOT LIKE '%noindex%' ) OR
pm.post_id IS NULL
)
AND p.post_type = '{$post_types}' AND p.post_status IN ( '" . join( "', '", esc_sql( $post_status ) ) . "' ) AND p.post_password = ''
AND p.ID != '{$posts_to_exclude}'
{$where_filter}
ORDER BY p.post_modified DESC LIMIT %d OFFSET %d
)
o JOIN {$wpdb->posts} l ON l.ID = o.ID
";
$posts = $wpdb->get_results( $wpdb->prepare( $sql, $count, $offset ) ); // phpcs:ignore
$post_ids = [];
foreach ( $posts as $post ) {
$post->post_status = 'publish';
$post->filter = 'sample';
$post_ids[] = $post->ID;
}
update_meta_cache( 'post', $post_ids );
return $posts;
}
/**
* Get where clause to query data.
*
* @param array $post_types Post types slug.
*
* @return string
*/
protected function get_sql_where_clause( $post_types ) {
global $wpdb;
$join = '';
$status = "{$wpdb->posts}.post_status = 'publish'";
// Based on WP_Query->get_posts(). R.
if ( in_array( 'attachment', $post_types, true ) ) {
$join = " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
$status = "p2.post_status = 'publish'";
}
$where_clause = "
{$join}
WHERE {$status}
AND {$wpdb->posts}.post_type IN ( '" . join( "', '", esc_sql( $post_types ) ) . "' )
AND {$wpdb->posts}.post_password = ''
";
return $where_clause;
}
/**
* Produce array of URL parts for given post object.
*
* @param object $post Post object to get URL parts for.
*
* @return array|boolean
*/
protected function get_url( $post ) {
$url = [];
/**
* Filter the post object before it gets added to the sitemap.
* This allows you to add custom properties to the post object, or replace it entirely.
*
* @param object $post Post object.
*/
$post = $this->do_filter( 'sitemap/post_object', $post );
if ( ! $post ) {
return false;
}
/**
* Filter the URL Rank Math SEO uses in the XML sitemap.
*
* Note that only absolute local URLs are allowed as the check after this removes external URLs.
*
* @param string $url URL to use in the XML sitemap
* @param object $post Post object for the URL.
*/
$url['loc'] = $this->do_filter( 'sitemap/xml_post_url', get_permalink( $post ), $post );
/**
* Do not include external URLs.
*
* @see https://wordpress.org/plugins/page-links-to/ can rewrite permalinks to external URLs.
*/
if ( 'external' === $this->get_classifier()->classify( $url['loc'] ) ) {
return false;
}
$modified = max( $post->post_modified_gmt, $post->post_date_gmt );
if ( '0000-00-00 00:00:00' !== $modified ) {
$url['mod'] = $modified;
}
$canonical = Helper::get_post_meta( 'canonical_url', $post->ID );
if ( '' !== $canonical && $canonical !== $url['loc'] ) {
/*
* Let's assume that if a canonical is set for this page and it's different from
* the URL of this post, that page is either already in the XML sitemap OR is on
* an external site, either way, we shouldn't include it here.
*/
return false;
}
$url['images'] = ! is_null( $this->get_image_parser() ) ? $this->get_image_parser()->get_images( $post ) : [];
return $url;
}
/**
* Get front page ID.
*
* @return int
*/
protected function get_page_on_front_id() {
if ( is_null( $this->page_on_front_id ) ) {
$this->page_on_front_id = intval( get_option( 'page_on_front' ) );
}
return $this->page_on_front_id;
}
/**
* Get page for posts ID.
*
* @return int
*/
protected function get_page_for_posts_id() {
if ( is_null( $this->page_for_posts_id ) ) {
$this->page_for_posts_id = intval( get_option( 'page_for_posts' ) );
}
return $this->page_for_posts_id;
}
/**
* Get the Image Parser.
*
* @return Image_Parser
*/
protected function get_image_parser() {
if ( is_null( $this->image_parser ) ) {
$this->image_parser = new Image_Parser();
}
return $this->image_parser;
}
/**
* Get the link classifier.
*
* @return Classifier
*/
protected function get_classifier() {
if ( is_null( $this->classifier ) ) {
$this->classifier = new Classifier( $this->get_home_url() );
}
return $this->classifier;
}
/**
* Get Home URL.
*
* This has been moved from the constructor because wp_rewrite is not available on plugins_loaded in multisite.
* It will now be requested on need and not on initialization.
*
* @return string
*/
protected function get_home_url() {
if ( is_null( $this->home_url ) ) {
$this->home_url = user_trailingslashit( get_home_url() );
}
return $this->home_url;
}
/**
* Get Blog page id.
*
* @return int
*/
private function get_blog_page_id() {
return get_option( 'show_on_front' ) === 'page' && $this->get_page_for_posts_id() ? $this->get_page_for_posts_id() : '';
}
}

View File

@@ -0,0 +1,316 @@
<?php
/**
* The sitemap provider for taxonomies.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Sitemap
* @author Rank Math <support@rankmath.com>
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
namespace RankMath\Sitemap\Providers;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Sitemap\Router;
use RankMath\Sitemap\Sitemap;
use RankMath\Sitemap\Image_Parser;
defined( 'ABSPATH' ) || exit;
/**
* Taxonomy provider
*/
class Taxonomy implements Provider {
use Hooker;
/**
* Holds image parser instance.
*
* @var Image_Parser
*/
protected static $image_parser;
/**
* Check if provider supports given item type.
*
* @param string $type Type string to check for.
* @return boolean
*/
public function handles_type( $type ) {
if ( is_a( $type, 'WP_Taxonomy' ) ) {
$type = $type->name;
}
if (
empty( $type ) ||
false === taxonomy_exists( $type ) ||
false === Helper::is_taxonomy_viewable( $type ) ||
false === Helper::is_taxonomy_indexable( $type ) ||
in_array( $type, [ 'link_category', 'nav_menu', 'post_format' ], true )
) {
return false;
}
/**
* Filter decision if taxonomy is excluded from the XML sitemap.
*
* @param bool $exclude Default false.
* @param string $type Taxonomy name.
*/
return ! $this->do_filter( 'sitemap/exclude_taxonomy', false, $type );
}
/**
* Get set of sitemaps index link data.
*
* @param int $max_entries Entries per sitemap.
* @return array
*/
public function get_index_links( $max_entries ) {
$taxonomies = Helper::get_accessible_taxonomies();
$taxonomies = array_filter( $taxonomies, [ $this, 'handles_type' ] );
if ( empty( $taxonomies ) ) {
return [];
}
// Retrieve all the taxonomies and their terms so we can do a proper count on them.
/**
* Filter the setting of excluding empty terms from the XML sitemap.
*
* @param boolean $exclude Defaults to true.
* @param array $taxonomy_names Array of names for the taxonomies being processed.
*/
$hide_empty = $this->do_filter( 'sitemap/exclude_empty_terms', true, $taxonomies );
$all_taxonomies = [];
foreach ( $taxonomies as $taxonomy_name => $object ) {
$all_taxonomies[ $taxonomy_name ] = get_terms(
$taxonomy_name,
[
'hide_empty' => $hide_empty,
'fields' => 'ids',
'orderby' => 'name',
'meta_query' => [
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
]
);
}
$index = [];
foreach ( $all_taxonomies as $tax_name => $terms ) {
if ( is_wp_error( $terms ) ) {
continue;
}
$max_pages = 1;
$total_count = empty( $terms ) ? 1 : count( $terms );
if ( $total_count > $max_entries ) {
$max_pages = (int) ceil( $total_count / $max_entries );
}
$tax = $taxonomies[ $tax_name ];
if ( ! is_array( $tax->object_type ) || count( $tax->object_type ) === 0 ) {
continue;
}
$last_modified_gmt = Sitemap::get_last_modified_gmt( $tax->object_type );
for ( $page_counter = 0; $page_counter < $max_pages; $page_counter++ ) {
$current_page = ( $max_pages > 1 ) ? ( $page_counter + 1 ) : '';
$terms_page = array_splice( $terms, 0, $max_entries );
if ( ! $terms_page ) {
continue;
}
$query = new \WP_Query(
[
'post_type' => $tax->object_type,
'tax_query' => [
[
'taxonomy' => $tax_name,
'terms' => $terms_page,
],
],
'orderby' => 'modified',
'order' => 'DESC',
'posts_per_page' => 1,
]
);
$item = $this->do_filter(
'sitemap/index/entry',
[
'loc' => Router::get_base_url( $tax_name . '-sitemap' . $current_page . '.xml' ),
'lastmod' => $query->have_posts() ? $query->posts[0]->post_modified_gmt : $last_modified_gmt,
],
'term',
$tax_name,
);
if ( ! $item ) {
continue;
}
$index[] = $item;
}
}
return $index;
}
/**
* Get set of sitemap link data.
*
* @param string $type Sitemap type.
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
* @return array
*/
public function get_sitemap_links( $type, $max_entries, $current_page ) {
$links = [];
$taxonomy = get_taxonomy( $type );
$terms = $this->get_terms( $taxonomy, $max_entries, $current_page );
Sitemap::maybe_redirect( count( $this->get_terms( $taxonomy, 0, $current_page ) ), $max_entries );
foreach ( $terms as $term ) {
$url = [];
if ( ! Sitemap::is_object_indexable( $term, 'term' ) ) {
continue;
}
$link = $this->get_term_link( $term );
if ( ! $link ) {
continue;
}
$url['loc'] = $link;
$url['mod'] = $this->get_lastmod( $term );
$url['images'] = ! is_null( $this->get_image_parser() ) ? $this->get_image_parser()->get_term_images( $term ) : [];
/** This filter is documented at inc/sitemaps/class-post-type-sitemap-provider.php */
$url = $this->do_filter( 'sitemap/entry', $url, 'term', $term );
if ( ! empty( $url ) ) {
$links[] = $url;
}
}
return $links;
}
/**
* Get the Image Parser.
*
* @return Image_Parser
*/
protected function get_image_parser() {
if ( class_exists( 'RankMath\Sitemap\Image_Parser' ) && ! isset( self::$image_parser ) ) {
self::$image_parser = new Image_Parser();
}
return self::$image_parser;
}
/**
* Get terms for taxonomy.
*
* @param object $taxonomy Taxonomy name.
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
* @return false|array
*/
private function get_terms( $taxonomy, $max_entries, $current_page ) {
$offset = $current_page > 1 ? ( ( $current_page - 1 ) * $max_entries ) : 0;
$hide_empty = ! Helper::get_settings( 'sitemap.tax_' . $taxonomy->name . '_include_empty' );
// Getting terms.
$terms = get_terms(
[
'taxonomy' => $taxonomy->name,
'orderby' => 'term_order',
'hide_empty' => $hide_empty,
'offset' => $offset,
'number' => $max_entries,
'exclude' => wp_parse_id_list( Helper::get_settings( 'sitemap.exclude_terms' ) ),
/*
* Limits aren't included in queries when hierarchical is set to true (by default).
*
* @link: https://github.com/WordPress/WordPress/blob/5.3/wp-includes/class-wp-term-query.php#L558-L567
*/
'hierarchical' => false,
'update_term_meta_cache' => false,
]
);
if ( is_wp_error( $terms ) || empty( $terms ) ) {
return [];
}
return $terms;
}
/**
* Get term link.
*
* @param WP_Term $term Term object.
* @return string
*/
private function get_term_link( $term ) {
$url = get_term_link( $term, $term->taxonomy );
$canonical = Helper::get_term_meta( 'canonical_url', $term, $term->taxonomy );
if ( $canonical && $canonical !== $url ) {
/*
* Let's assume that if a canonical is set for this term and it's different from
* the URL of this term, that page is either already in the XML sitemap OR is on
* an external site, either way, we shouldn't include it here.
*/
return false;
}
return $url;
}
/**
* Get last modified date of post by term.
*
* @param WP_Term $term Term object.
* @return string
*/
public function get_lastmod( $term ) {
global $wpdb;
return $wpdb->get_var(
$wpdb->prepare(
"
SELECT MAX(p.post_modified_gmt) AS lastmod
FROM $wpdb->posts AS p
INNER JOIN $wpdb->term_relationships AS term_rel
ON term_rel.object_id = p.ID
INNER JOIN $wpdb->term_taxonomy AS term_tax
ON term_tax.term_taxonomy_id = term_rel.term_taxonomy_id
AND term_tax.taxonomy = %s
AND term_tax.term_id = %d
WHERE p.post_status IN ('publish', 'inherit')
AND p.post_password = ''
",
$term->taxonomy,
$term->term_id
)
);
}
}

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,48 @@
<?php
/**
* The sitemap provider interface.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Sitemap
* @author Rank Math <support@rankmath.com>
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
namespace RankMath\Sitemap\Providers;
defined( 'ABSPATH' ) || exit;
/**
* Provider interface.
*/
interface Provider {
/**
* Check if provider supports given item type.
*
* @param string $type Type string to check for.
* @return boolean
*/
public function handles_type( $type );
/**
* Get set of sitemaps index link data.
*
* @param int $max_entries Entries per sitemap.
* @return array
*/
public function get_index_links( $max_entries );
/**
* Get set of sitemap link data.
*
* @param string $type Sitemap type.
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
* @return array
*/
public function get_sitemap_links( $type, $max_entries, $current_page );
}