Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
@@ -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() : '';
|
||||
}
|
||||
}
|
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
<?php // Silence is golden.
|
@@ -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 );
|
||||
}
|
Reference in New Issue
Block a user