Создание Провайдера для Карты сайта
Система Карты сайта WordPress, как и многие другие части, позволяет довольно просто расширять функциональность и добавлять произвольные ссылки в существующую Карту сайта. Ниже рассмотрим как это делается.
Что кастомное автоматически добавляется в Карту сайта?
Если вы создаете дополнительные (кастомные) типы записей или таксономии, то эти сущности автоматически попадут в Карту сайта WordPress. Единственное что для этого нужно, это чтобы новый тип записи или таксономия были «публичные»: имели параметры public = true и publicly_queryable = true. Эти параметры указываются при регистрации типа записи или таксономии.
Создание своего провайдера для Карты сайта
Но если ваш плагин или тема, имеют какие-то свои сущности, которые нужно добавить в карту сайта, то для них нужно будет создать нового провайдера. Это пользовательский класс PHP, который расширяет абстрактный класс WP_Sitemaps_Provider.
Созданный Класс, нужно зарегистрировать (подключить) с помощью функции wp_register_sitemap_provider():
add_filter( 'init', function(){
$provider = new Awesome_Plugin_Sitemaps_Provider();
wp_register_sitemap_provider( 'awesome-plugin', $provider );
} );
Этот провайдер будет отвечать за отображение всех новых Карт сайта, их пагинацию вывод карт для отдельных элементов (ссылок).
Примеры создания Провайдеров
#1 Свой провайдер с двумя типами и кастомной таблицей
Допустим у нас в БД есть таблица, в которой хранятся медиа данные об audio и video сущностях. Каждая такая сущность имеет свою страницу на фронте. Нам нужно добавить все эти страницы в Карту сайта.
Создадим своего провайдера, назовем его megamedia. Для этого создадим в теме файл class-Megamedia_Sitemaps_Provider.php со следующим кодом:
class Media_Sitemaps_Provider extends WP_Sitemaps_Provider {
// make visibility not protected
public $name;
/**
* Constructor. Sets name, object_type properties.
*
* $name Provider name. Uses in URL (must be unique).
* $object_type The object name that the provider works with.
* Passes into the hooks (must be unique).
*/
public function __construct() {
$this->name = 'megamedia';
$this->object_type = 'megamedia';
}
/**
* Returns the list of supported object subtypes exposed by the provider.
*
* @return array List of object subtypes objects keyed by their name.
*/
public function get_object_subtypes() {
return array(
'audio' => new stdClass(),
'video' => new stdClass()
);
}
/**
* Gets a URL list for a sitemap.
*
* @param int $page_num Page of results.
* @param string $subtype Optional. Object subtype name. Default empty.
*
* @return array Array of URLs for a sitemap.
*/
public function get_url_list( $page_num, $subtype = '' ) {
$result = $this->db_query( [
'subtype' => $subtype,
'paged' => $page_num,
] );
$url_list = array();
foreach ( $result as $megamedia ) {
$sitemap_entry = [
'loc' => home_url( "/megamedia/$subtype/$megamedia->id" ),
// 'priority' => 0.5,
// 'changefreq' => 'monthly',
];
$url_list[] = $sitemap_entry;
}
return $url_list;
}
/**
* Gets the max number of pages available for the object type.
*
* @param string $subtype Optional. Object subtype. Default empty.
* @return int Total number of pages.
*/
public function get_max_num_pages( $subtype = '' ) {
$total = $this->db_query( [
'subtype' => $subtype,
'count' => true,
] );
return (int) ceil( $total / wp_sitemaps_get_max_urls( $this->object_type ) );
}
/**
* Returns the SQL query result.
*
* @return array Array of query arguments.
*/
protected function db_query( $args ) {
global $wpdb;
$arg = (object) array_merge( [
'paged' => 1,
'subtype' => 'audio',
'count' => false,
], $args );
$SELECT = $arg->count ? 'count(*)' : '*';
$WHERE = [];
$WHERE[] = 'post_id = 0';
$WHERE[] = $wpdb->prepare( "media_type = %s", $arg->subtype );
$WHERE = implode( ' AND ', $WHERE );
$per_page = wp_sitemaps_get_max_urls( $this->object_type );
$offset = ( $arg->paged - 1 ) * $per_page;
$LIMIT = sprintf( "LIMIT %d, %d", $offset,$per_page );
$sql = "SELECT $SELECT FROM $wpdb->wp_core_data WHERE $WHERE $LIMIT";
$result = $arg->count ? $wpdb->get_var( $sql ) : $wpdb->get_results( $sql );
return $result;
}
}
Теперь подключим (зарегистрируем) созданного провайдера в файле functions.php.
add_filter( 'init', 'wpkama_register_sitemap_providers' );
function wpkama_register_sitemap_providers(){
require_once __DIR__ .'/class-Megamedia_Sitemaps_Provider.php';
$provider = new Megamedia_Sitemaps_Provider();
wp_register_sitemap_provider( $provider->name, $provider );
}
Переходим в Карту сайта и видим:
Заметки:
ВАЖНО: первый параметр функции wp_register_sitemap_provider() должен быть такой же как свойство $name у провайдера! И состоять это имя может только из символов a-z!
Свойства класса WP_Sitemaps_Provider:
- $this->name
Имя провайдера. Используется в URL карты сайта. Должно быть уникальным.
ВАЖНО! Разрешаются только символы
a-z. Т.е. нельзя использовать тире, пробелы и строчные. Неправильно:similar_posts,similar-posts,Similar. Правильноsimilarposts.- $this->object_type
- Имя объекта с которым работает провайдер (post, term, user). Используется в хуках. Должно быть уникальным.
Методы класса Media_Sitemaps_Provider и WP_Sitemaps_Provider:
- get_object_subtypes()
- Должен вернуть список подтипов, например у постов это типы постов. Возвращает массив объектов, в ключах находятся имена подтипов.
- get_url_list( $page_num, $subtype = '' )
Должен вернуть список ссылок для каждой карты — список данных для XML тегов <url>. Выглядит этот список как массив массивов, каждый вложенный массив - это каждая ссылка. Например:
$url_list = [ [ 'loc'=> 'https://example.com/megamedia/audio/2610735' ], [ 'loc'=> 'https://example.com/megamedia/audio/9514241' ], ... ];
- get_max_num_pages( $subtype = '' )
- Должен вернуть число - общее кол-во элементов для переданного подтипа. Например для записей WP - это сколько всего записей указанного типа записи, например, сколько всего страниц (page).
- db_query( $args )
- Это произвольный свой метод класса, который создает запрос в БД и получает данные по переданным параметрам, в том числе тут учитывается подтип и пагинация.
Используемые Функции:
- wp_sitemaps_get_max_urls()
- Внешняя функция, которая возвращает макс. кол-во элементов в каждой карте сайта. По умолчанию 2000.
#2 Провайдер на основе постов
Допустим мы доработали URL постов и теперь если в конец ссылки поста дописать /similar_posts/ мы попадаем на страницу с похожими записями. Нам нужно добавить все такие ссылки в Карту сайта.
Назовем провайдера similarposts (в названии нельзя указывать пробелы и тире!) и создадим класс провайдера, так:
class Similar_Posts_Sitemaps_Provider extends WP_Sitemaps_Provider {
// make visibility not protected
public $name;
public function __construct() {
$this->name = 'similarposts';
$this->object_type = 'similarposts';
}
public function get_url_list( $page_num, $subtype = '' ) {
$args = $this->wp_query_args();
$args['paged'] = $page_num;
$query = new WP_Query( $args );
$url_list = array();
foreach ( $query->posts as $post ) {
$sitemap_entry = [
'loc' => user_trailingslashit( untrailingslashit( get_permalink( $post ) ) .'/similar_posts/' ),
];
$url_list[] = $sitemap_entry;
}
return $url_list;
}
public function get_max_num_pages( $subtype = '' ) {
$args = $this->wp_query_args();
$args['fields'] = 'ids';
$args['no_found_rows'] = false;
$query = new WP_Query( $args );
return $query->max_num_pages;
}
protected function wp_query_args(){
return array(
'orderby' => 'ID',
'order' => 'ASC',
'post_type' => 'post',
'posts_per_page' => wp_sitemaps_get_max_urls( $this->object_type ),
'post_status' => array( 'publish' ),
'no_found_rows' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
);
}
}
Теперь зарегистрируем его:
add_filter( 'init', 'wpkama_register_sitemap_providers' );
function wpkama_register_sitemap_providers(){
require_once __DIR__ .'/class-Similar_Posts_Sitemaps_Provider.php';
$provider = new Similar_Posts_Sitemaps_Provider();
wp_register_sitemap_provider( $provider->name, $provider );
}
Готово! Идем в карту сайта:
#3 Примеры из ядра
Из коробки в WP есть три провайдера (поставщика) карт сайтов для разных типов. Их код можно взять за основу для создания своего провайдера.
posts— WP_Sitemaps_Posts{}taxonomies— WP_Sitemaps_Taxonomies{}users— WP_Sitemaps_Users{}



